diff options
author | Holger Ihrig <holger.ihrig@nokia.com> | 2011-08-24 12:53:32 +0200 |
---|---|---|
committer | Holger Ihrig <holger.ihrig@nokia.com> | 2011-08-31 10:08:38 +0200 |
commit | 012ba8c0e5270f962dbc891039c32f49d31c565b (patch) | |
tree | 499a88b02862551708eb0f2c0f366afa8b998054 /tests/auto/corelib/io | |
parent | a7d682dd9c9271d137d5aa73a9192a812492a596 (diff) |
Moving relevant tests to corelib/io
Marked Test for qdiriterator as insignificant. See QTBUG-21160
Marked Test for qresourceengine as insignificant. See QTBUG-21159
Task-number: QTBUG-21066
Change-Id: I72848a651ff3e7aff1d6105dd49124e4ed070a44
Reviewed-on: http://codereview.qt.nokia.com/3577
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
Reviewed-by: Jason McDonald <jason.mcdonald@nokia.com>
Diffstat (limited to 'tests/auto/corelib/io')
1211 files changed, 49505 insertions, 0 deletions
diff --git a/tests/auto/corelib/io/io.pro b/tests/auto/corelib/io/io.pro new file mode 100644 index 0000000000..cbe2b609b9 --- /dev/null +++ b/tests/auto/corelib/io/io.pro @@ -0,0 +1,23 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qabstractfileengine \ + qbuffer \ + qdatastream \ + qdebug \ + qdir \ + qdiriterator \ + qfile \ + qfileinfo \ + qfilesystementry \ + qfilesystemwatcher \ + qiodevice \ + qprocess \ + qprocessenvironment \ + qresourceengine \ + qsettings \ + qtemporaryfile \ + qtextstream \ + qurl \ + +!contains(QT_CONFIG, private_tests): SUBDIRS -= \ + qfileinfo diff --git a/tests/auto/corelib/io/qabstractfileengine/qabstractfileengine.pro b/tests/auto/corelib/io/qabstractfileengine/qabstractfileengine.pro new file mode 100644 index 0000000000..870473a4cb --- /dev/null +++ b/tests/auto/corelib/io/qabstractfileengine/qabstractfileengine.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT = core + +SOURCES = tst_qabstractfileengine.cpp +RESOURCES += qabstractfileengine.qrc + diff --git a/tests/auto/corelib/io/qabstractfileengine/qabstractfileengine.qrc b/tests/auto/corelib/io/qabstractfileengine/qabstractfileengine.qrc new file mode 100644 index 0000000000..5401b086b2 --- /dev/null +++ b/tests/auto/corelib/io/qabstractfileengine/qabstractfileengine.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/tst_qabstractfileengine/"> + <file>resources/</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qabstractfileengine/resources/file.txt b/tests/auto/corelib/io/qabstractfileengine/resources/file.txt new file mode 100644 index 0000000000..8a03e0e55f --- /dev/null +++ b/tests/auto/corelib/io/qabstractfileengine/resources/file.txt @@ -0,0 +1 @@ +This is a simple text file. diff --git a/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp new file mode 100644 index 0000000000..a81633341d --- /dev/null +++ b/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp @@ -0,0 +1,794 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QAbstractFileEngine> +#include <QtCore/QFSFileEngine> + +#include <QtCore/QMutex> +#include <QtCore/QMutexLocker> +#include <QtCore/QSharedPointer> +#include <QtCore/QScopedPointer> +#include <QtCore/QHash> + +#include <QtTest/QTest> + +#include <QtCore/QDebug> + +class tst_QAbstractFileEngine + : public QObject +{ + Q_OBJECT +public slots: + void cleanupTestCase(); + +private slots: + void customHandler(); + + void fileIO_data(); + void fileIO(); + +private: + QStringList filesForRemoval; +}; + +class ReferenceFileEngine + : public QAbstractFileEngine +{ +public: + ReferenceFileEngine(const QString &fileName) + : fileName_(fileName) + , position_(-1) + , openForRead_(false) + , openForWrite_(false) + { + } + + bool open(QIODevice::OpenMode openMode) + { + if (openForRead_ || openForWrite_) { + qWarning("%s: file is already open for %s", + Q_FUNC_INFO, + (openForRead_ ? "reading" : "writing")); + return false; + } + + openFile_ = resolveFile(openMode & QIODevice::WriteOnly); + if (!openFile_) + return false; + + position_ = 0; + if (openMode & QIODevice::ReadOnly) + openForRead_ = true; + + if (openMode & QIODevice::WriteOnly) { + openForWrite_ = true; + + QMutexLocker lock(&openFile_->mutex); + if (openMode & QIODevice::Truncate + || !(openForRead_ || openMode & QIODevice::Append)) + openFile_->content.clear(); + + if (openMode & QIODevice::Append) + position_ = openFile_->content.size(); + } + + return true; + } + + bool close() + { + openFile_.clear(); + + openForRead_ = false; + openForWrite_ = false; + position_ = -1; + + return true; + } + + qint64 size() const + { + QSharedPointer<File> file = resolveFile(false); + if (!file) + return 0; + + QMutexLocker lock(&file->mutex); + return file->content.size(); + } + + qint64 pos() const + { + if (!openForRead_ && !openForWrite_) { + qWarning("%s: file is not open", Q_FUNC_INFO); + return -1; + } + return position_; + } + + bool seek(qint64 pos) + { + if (!openForRead_ && !openForWrite_) { + qWarning("%s: file is not open", Q_FUNC_INFO); + return false; + } + + if (pos >= 0) { + position_ = pos; + return true; + } + + return false; + } + + bool flush() + { + if (!openForRead_ && !openForWrite_) { + qWarning("%s: file is not open", Q_FUNC_INFO); + return false; + } + + return true; + } + + bool remove() + { + QMutexLocker lock(&fileSystemMutex); + int count = fileSystem.remove(fileName_); + + return (count == 1); + } + + bool copy(const QString &newName) + { + QMutexLocker lock(&fileSystemMutex); + if (!fileSystem.contains(fileName_) + || fileSystem.contains(newName)) + return false; + + fileSystem.insert(newName, fileSystem.value(fileName_)); + return true; + } + + bool rename(const QString &newName) + { + QMutexLocker lock(&fileSystemMutex); + if (!fileSystem.contains(fileName_) + || fileSystem.contains(newName)) + return false; + + fileSystem.insert(newName, fileSystem.take(fileName_)); + return true; + } + + // bool link(const QString &newName) + // { + // Q_UNUSED(newName) + // return false; + // } + + // bool mkdir(const QString &dirName, bool createParentDirectories) const + // { + // Q_UNUSED(dirName) + // Q_UNUSED(createParentDirectories) + + // return false; + // } + + // bool rmdir(const QString &dirName, bool recurseParentDirectories) const + // { + // Q_UNUSED(dirName) + // Q_UNUSED(recurseParentDirectories) + + // return false; + // } + + bool setSize(qint64 size) + { + if (size < 0) + return false; + + QSharedPointer<File> file = resolveFile(false); + if (!file) + return false; + + QMutexLocker lock(&file->mutex); + file->content.resize(size); + + if (openForRead_ || openForWrite_) + if (position_ > size) + position_ = size; + + return (file->content.size() == size); + } + + FileFlags fileFlags(FileFlags type) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + QMutexLocker lock(&file->mutex); + return (file->fileFlags & type); + } + + return FileFlags(); + } + + // bool setPermissions(uint perms) + // { + // Q_UNUSED(perms) + + // return false; + // } + + QString fileName(FileName file) const + { + switch (file) { + case DefaultName: + return QLatin1String("DefaultName"); + case BaseName: + return QLatin1String("BaseName"); + case PathName: + return QLatin1String("PathName"); + case AbsoluteName: + return QLatin1String("AbsoluteName"); + case AbsolutePathName: + return QLatin1String("AbsolutePathName"); + case LinkName: + return QLatin1String("LinkName"); + case CanonicalName: + return QLatin1String("CanonicalName"); + case CanonicalPathName: + return QLatin1String("CanonicalPathName"); + case BundleName: + return QLatin1String("BundleName"); + + default: + break; + } + + return QString(); + } + + uint ownerId(FileOwner owner) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + switch (owner) { + case OwnerUser: + { + QMutexLocker lock(&file->mutex); + return file->userId; + } + case OwnerGroup: + { + QMutexLocker lock(&file->mutex); + return file->groupId; + } + } + } + + return -2; + } + + QString owner(FileOwner owner) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + uint ownerId; + switch (owner) { + case OwnerUser: + { + QMutexLocker lock(&file->mutex); + ownerId = file->userId; + } + + { + QMutexLocker lock(&fileSystemMutex); + return fileSystemUsers.value(ownerId); + } + + case OwnerGroup: + { + QMutexLocker lock(&file->mutex); + ownerId = file->groupId; + } + + { + QMutexLocker lock(&fileSystemMutex); + return fileSystemGroups.value(ownerId); + } + } + } + + return QString(); + } + + QDateTime fileTime(FileTime time) const + { + QSharedPointer<File> file = resolveFile(false); + if (file) { + QMutexLocker lock(&file->mutex); + switch (time) { + case CreationTime: + return file->creation; + case ModificationTime: + return file->modification; + case AccessTime: + return file->access; + } + } + + return QDateTime(); + } + + void setFileName(const QString &file) + { + if (openForRead_ || openForWrite_) + qWarning("%s: Can't set file name while file is open", Q_FUNC_INFO); + else + fileName_ = file; + } + + // typedef QAbstractFileEngineIterator Iterator; + // Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) + // { + // Q_UNUSED(filters) + // Q_UNUSED(filterNames) + + // return 0; + // } + + // Iterator *endEntryList() + // { + // return 0; + // } + + qint64 read(char *data, qint64 maxLen) + { + if (!openForRead_) { + qWarning("%s: file must be open for reading", Q_FUNC_INFO); + return -1; + } + + if (openFile_.isNull()) { + qWarning("%s: file must not be null", Q_FUNC_INFO); + return -1; + } + + QMutexLocker lock(&openFile_->mutex); + qint64 readSize = qMin(openFile_->content.size() - position_, maxLen); + if (readSize < 0) + return -1; + + qMemCopy(data, openFile_->content.constData() + position_, readSize); + position_ += readSize; + + return readSize; + } + + qint64 write(const char *data, qint64 length) + { + if (!openForWrite_) { + qWarning("%s: file must be open for writing", Q_FUNC_INFO); + return -1; + } + + if (openFile_.isNull()) { + qWarning("%s: file must not be null", Q_FUNC_INFO); + return -1; + } + + if (length < 0) + return -1; + + QMutexLocker lock(&openFile_->mutex); + if (openFile_->content.size() == position_) + openFile_->content.append(data, length); + else { + if (position_ + length > openFile_->content.size()) + openFile_->content.resize(position_ + length); + openFile_->content.replace(position_, length, data, length); + } + + qint64 writeSize = qMin(length, openFile_->content.size() - position_); + position_ += writeSize; + + return writeSize; + } + +protected: + // void setError(QFile::FileError error, const QString &str); + + struct File + { + File() + : userId(0) + , groupId(0) + , fileFlags( + ReadOwnerPerm | WriteOwnerPerm | ExeOwnerPerm + | ReadUserPerm | WriteUserPerm | ExeUserPerm + | ReadGroupPerm | WriteGroupPerm | ExeGroupPerm + | ReadOtherPerm | WriteOtherPerm | ExeOtherPerm + | FileType | ExistsFlag) + { + } + + QMutex mutex; + + uint userId, groupId; + QAbstractFileEngine::FileFlags fileFlags; + QDateTime creation, modification, access; + + QByteArray content; + }; + + QSharedPointer<File> resolveFile(bool create) const + { + if (openForRead_ || openForWrite_) { + if (!openFile_) + qWarning("%s: file should not be null", Q_FUNC_INFO); + return openFile_; + } + + QMutexLocker lock(&fileSystemMutex); + if (create) { + QSharedPointer<File> &p = fileSystem[fileName_]; + if (p.isNull()) + p = QSharedPointer<File>(new File); + return p; + } + + return fileSystem.value(fileName_); + } + + static QMutex fileSystemMutex; + static QHash<uint, QString> fileSystemUsers, fileSystemGroups; + static QHash<QString, QSharedPointer<File> > fileSystem; + +private: + QString fileName_; + qint64 position_; + bool openForRead_; + bool openForWrite_; + + mutable QSharedPointer<File> openFile_; +}; + +QMutex ReferenceFileEngine::fileSystemMutex; +QHash<uint, QString> ReferenceFileEngine::fileSystemUsers, ReferenceFileEngine::fileSystemGroups; +QHash<QString, QSharedPointer<ReferenceFileEngine::File> > ReferenceFileEngine::fileSystem; + +class FileEngineHandler + : QAbstractFileEngineHandler +{ + QAbstractFileEngine *create(const QString &fileName) const + { + if (fileName.startsWith("QFSFileEngine:")) + return new QFSFileEngine(fileName.mid(14)); + if (fileName.startsWith("reference-file-engine:")) + return new ReferenceFileEngine(fileName.mid(22)); + if (fileName.startsWith("resource:")) + return QAbstractFileEngine::create(QLatin1String(":/tst_qabstractfileengine/resources/") + fileName.mid(9)); + return 0; + } +}; + +void tst_QAbstractFileEngine::cleanupTestCase() +{ + bool failed = false; + + FileEngineHandler handler; + Q_FOREACH(QString file, filesForRemoval) + if (!QFile::remove(file) + || QFile::exists(file)) { + failed = true; + qDebug() << "Couldn't remove file:" << file; + } + + QVERIFY(!failed); +} + +void tst_QAbstractFileEngine::customHandler() +{ + QScopedPointer<QAbstractFileEngine> file; + { + file.reset(QAbstractFileEngine::create("resource:file.txt")); + + QVERIFY(file); + } + + { + FileEngineHandler handler; + + QFile file("resource:file.txt"); + QVERIFY(file.exists()); + } + + { + QFile file("resource:file.txt"); + QVERIFY(!file.exists()); + } +} + +void tst_QAbstractFileEngine::fileIO_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("readContent"); + QTest::addColumn<QByteArray>("writeContent"); + QTest::addColumn<bool>("fileExists"); + + QString resourceTxtFile(":/tst_qabstractfileengine/resources/file.txt"); + QByteArray readContent("This is a simple text file.\n"); + QByteArray writeContent("This contains two lines of text.\n"); + + QTest::newRow("resource") << resourceTxtFile << readContent << QByteArray() << true; + QTest::newRow("native") << "native-file.txt" << readContent << writeContent << false; + QTest::newRow("Forced QFSFileEngine") << "QFSFileEngine:QFSFileEngine-file.txt" << readContent << writeContent << false; + QTest::newRow("Custom FE") << "reference-file-engine:file.txt" << readContent << writeContent << false; + + QTest::newRow("Forced QFSFileEngine (native)") << "QFSFileEngine:native-file.txt" << readContent << writeContent << true; + QTest::newRow("native (Forced QFSFileEngine)") << "QFSFileEngine-file.txt" << readContent << writeContent << true; + QTest::newRow("Custom FE (2)") << "reference-file-engine:file.txt" << readContent << writeContent << true; +} + +void tst_QAbstractFileEngine::fileIO() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, readContent); + QFETCH(QByteArray, writeContent); + QFETCH(bool, fileExists); + + FileEngineHandler handler; + + + { + QFile file(fileName); + QCOMPARE(file.exists(), fileExists); + + if (!fileExists) { + QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Unbuffered)); + filesForRemoval.append(fileName); + + QCOMPARE(file.write(readContent), qint64(readContent.size())); + } + } + + // + // File content is: readContent + // + + qint64 fileSize = readContent.size(); + { + // Reading + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.readAll(), readContent); + QCOMPARE(file.pos(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + if (writeContent.isEmpty()) + return; + + { + // Writing / appending + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), fileSize); + + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + + fileSize += writeContent.size(); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: readContent + writeContent + // + + { + // Reading and Writing + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QCOMPARE(file.readAll(), readContent + writeContent); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(writeContent.size())); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QCOMPARE(file.write(readContent), qint64(readContent.size())); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(0)); + QCOMPARE(file.pos(), qint64(0)); + QCOMPARE(file.size(), fileSize); + + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(0)); + QCOMPARE(file.read(writeContent.size()), writeContent); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QCOMPARE(file.readAll(), readContent); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: writeContent + readContent + // + + { + // Writing + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), qint64(writeContent.size())); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.resize(writeContent.size())); + QCOMPARE(file.size(), qint64(writeContent.size())); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), qint64(writeContent.size())); + + QVERIFY(file.resize(fileSize)); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: writeContent + <undefined> + // File size is : (readContent + writeContent).size() + // + + { + // Writing / extending + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), fileSize); + QCOMPARE(file.pos(), qint64(0)); + + QVERIFY(file.seek(1024)); + QCOMPARE(file.pos(), qint64(1024)); + QCOMPARE(file.size(), fileSize); + + fileSize = 1024 + writeContent.size(); + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + QVERIFY(file.seek(1028)); + QCOMPARE(file.pos(), qint64(1028)); + QCOMPARE(file.size(), fileSize); + + fileSize = 1028 + writeContent.size(); + QCOMPARE(file.write(writeContent), qint64(writeContent.size())); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: writeContent + <undefined> + writeContent + // File size is : 1024 + writeContent.size() + // + + { + // Writing / truncating + QFile file(fileName); + + QVERIFY(!file.isOpen()); + QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Unbuffered)); + + QVERIFY(file.isOpen()); + QCOMPARE(file.size(), qint64(0)); + QCOMPARE(file.pos(), qint64(0)); + + fileSize = readContent.size(); + QCOMPARE(file.write(readContent), fileSize); + QCOMPARE(file.pos(), fileSize); + QCOMPARE(file.size(), fileSize); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.size(), fileSize); + } + + // + // File content is: readContent + // +} + +QTEST_APPLESS_MAIN(tst_QAbstractFileEngine) +#include "tst_qabstractfileengine.moc" + diff --git a/tests/auto/corelib/io/qbuffer/.gitignore b/tests/auto/corelib/io/qbuffer/.gitignore new file mode 100644 index 0000000000..40447ec0db --- /dev/null +++ b/tests/auto/corelib/io/qbuffer/.gitignore @@ -0,0 +1 @@ +tst_qbuffer diff --git a/tests/auto/corelib/io/qbuffer/qbuffer.pro b/tests/auto/corelib/io/qbuffer/qbuffer.pro new file mode 100644 index 0000000000..b768eb82d8 --- /dev/null +++ b/tests/auto/corelib/io/qbuffer/qbuffer.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qbuffer.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp new file mode 100644 index 0000000000..bf4842ff94 --- /dev/null +++ b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp @@ -0,0 +1,608 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <QBuffer> +#include <QByteArray> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QBuffer : public QObject +{ + Q_OBJECT +public: + tst_QBuffer(); + +private slots: + void open(); + void getSetCheck(); + void readBlock(); + void readBlockPastEnd(); + void writeBlock_data(); + void writeBlock(); + void seek(); + void seekTest_data(); + void seekTest(); + void read_rawdata(); + void isSequential(); + void signalTest_data(); + void signalTest(); + void isClosedAfterClose(); + void readLine_data(); + void readLine(); + void canReadLine_data(); + void canReadLine(); + void atEnd(); + void readLineBoundaries(); + void writeAfterQByteArrayResize(); + void read_null(); + +protected slots: + void readyReadSlot(); + void bytesWrittenSlot(qint64 written); + +private: + qint64 totalBytesWritten; + bool gotReadyRead; +}; + +// Testing get/set functions +void tst_QBuffer::getSetCheck() +{ + QBuffer obj1; + // const QByteArray & QBuffer::data() + // void QBuffer::setData(const QByteArray &) + QByteArray var1("Bogus data"); + obj1.setData(var1); + QCOMPARE(var1, obj1.data()); + obj1.setData(QByteArray()); + QCOMPARE(QByteArray(), obj1.data()); +} + +tst_QBuffer::tst_QBuffer() +{ +} + +void tst_QBuffer::open() +{ + QByteArray data(10, 'f'); + + QBuffer b; + + QTest::ignoreMessage(QtWarningMsg, "QBuffer::open: Buffer access not specified"); + QVERIFY(!b.open(QIODevice::NotOpen)); + QVERIFY(!b.isOpen()); + b.close(); + + QTest::ignoreMessage(QtWarningMsg, "QBuffer::open: Buffer access not specified"); + QVERIFY(!b.open(QIODevice::Text)); + QVERIFY(!b.isOpen()); + b.close(); + + QTest::ignoreMessage(QtWarningMsg, "QBuffer::open: Buffer access not specified"); + QVERIFY(!b.open(QIODevice::Unbuffered)); + QVERIFY(!b.isOpen()); + b.close(); + + QVERIFY(b.open(QIODevice::ReadOnly)); + QVERIFY(b.isReadable()); + b.close(); + + QVERIFY(b.open(QIODevice::WriteOnly)); + QVERIFY(b.isWritable()); + b.close(); + + b.setData(data); + QVERIFY(b.open(QIODevice::Append)); + QVERIFY(b.isWritable()); + QCOMPARE(b.size(), qint64(10)); + QCOMPARE(b.pos(), b.size()); + b.close(); + + b.setData(data); + QVERIFY(b.open(QIODevice::Truncate)); + QVERIFY(b.isWritable()); + QCOMPARE(b.size(), qint64(0)); + QCOMPARE(b.pos(), qint64(0)); + b.close(); + + QVERIFY(b.open(QIODevice::ReadWrite)); + QVERIFY(b.isReadable()); + QVERIFY(b.isWritable()); + b.close(); +} + +// some status() tests, too +void tst_QBuffer::readBlock() +{ +// QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: File not open"); +// QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: Read operation not permitted"); + + const int arraySize = 10; + char a[arraySize]; + QBuffer b; + QCOMPARE(b.read(a, arraySize), (qint64) -1); // not opened + QVERIFY(b.atEnd()); + + QByteArray ba; + ba.resize(arraySize); + b.setBuffer(&ba); + b.open(QIODevice::WriteOnly); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device"); + QCOMPARE(b.read(a, arraySize), (qint64) -1); // no read access + b.close(); + + b.open(QIODevice::ReadOnly); + QCOMPARE(b.read(a, arraySize), (qint64) arraySize); + QVERIFY(b.atEnd()); + + // up to 3.0.x reading beyond the end was an error while ok + // this has been made consistent with other QIODevice sub classes in 3.1 + QCOMPARE(b.read(a, 1), qint64(0)); + QVERIFY(b.atEnd()); + + // read in two chunks + b.close(); + b.open(QIODevice::ReadOnly); + QCOMPARE(b.read(a, arraySize/2), (qint64) arraySize/2); + QCOMPARE(b.read(a + arraySize/2, arraySize - arraySize/2), + (qint64)(arraySize - arraySize/2)); + QVERIFY(b.atEnd()); +} + +void tst_QBuffer::readBlockPastEnd() +{ + QByteArray arr(4096 + 3616, 'd'); + QBuffer buf(&arr); + + buf.open(QIODevice::ReadOnly); + char dummy[4096]; + + buf.read(1); + + QCOMPARE(buf.read(dummy, 4096), qint64(4096)); + QCOMPARE(buf.read(dummy, 4096), qint64(3615)); + QVERIFY(buf.atEnd()); +} + +void tst_QBuffer::writeBlock_data() +{ + QTest::addColumn<QString>("str"); + + QTest::newRow( "small_bytearray" ) << QString("Test"); + QTest::newRow( "large_bytearray" ) << QString("The QBuffer class is an I/O device that operates on a QByteArray.\n" + "QBuffer is used to read and write to a memory buffer. It is normally " + "used with a QTextStream or a QDataStream. QBuffer has an associated " + "QByteArray which holds the buffer data. The size() of the buffer is " + "automatically adjusted as data is written.\n" + "The constructor QBuffer(QByteArray) creates a QBuffer using an existing " + "byte array. The byte array can also be set with setBuffer(). Writing to " + "the QBuffer will modify the original byte array because QByteArray is " + "explicitly shared.\n" + "Use open() to open the buffer before use and to set the mode (read-only, " + "write-only, etc.). close() closes the buffer. The buffer must be closed " + "before reopening or calling setBuffer().\n" + "A common way to use QBuffer is through QDataStream or QTextStream, which " + "have constructors that take a QBuffer parameter. For convenience, there " + "are also QDataStream and QTextStream constructors that take a QByteArray " + "parameter. These constructors create and open an internal QBuffer.\n" + "Note that QTextStream can also operate on a QString (a Unicode string); a " + "QBuffer cannot.\n" + "You can also use QBuffer directly through the standard QIODevice functions " + "readBlock(), writeBlock() readLine(), at(), getch(), putch() and ungetch().\n" + "See also QFile, QDataStream, QTextStream, QByteArray, Shared Classes, Collection " + "Classes and Input/Output and Networking.\n\n" + "The QBuffer class is an I/O device that operates on a QByteArray.\n" + "QBuffer is used to read and write to a memory buffer. It is normally " + "used with a QTextStream or a QDataStream. QBuffer has an associated " + "QByteArray which holds the buffer data. The size() of the buffer is " + "automatically adjusted as data is written.\n" + "The constructor QBuffer(QByteArray) creates a QBuffer using an existing " + "byte array. The byte array can also be set with setBuffer(). Writing to " + "the QBuffer will modify the original byte array because QByteArray is " + "explicitly shared.\n" + "Use open() to open the buffer before use and to set the mode (read-only, " + "write-only, etc.). close() closes the buffer. The buffer must be closed " + "before reopening or calling setBuffer().\n" + "A common way to use QBuffer is through QDataStream or QTextStream, which " + "have constructors that take a QBuffer parameter. For convenience, there " + "are also QDataStream and QTextStream constructors that take a QByteArray " + "parameter. These constructors create and open an internal QBuffer.\n" + "Note that QTextStream can also operate on a QString (a Unicode string); a " + "QBuffer cannot.\n" + "You can also use QBuffer directly through the standard QIODevice functions " + "readBlock(), writeBlock() readLine(), at(), getch(), putch() and ungetch().\n" + "See also QFile, QDataStream, QTextStream, QByteArray, Shared Classes, Collection " + "Classes and Input/Output and Networking.\n\n" + "The QBuffer class is an I/O device that operates on a QByteArray.\n" + "QBuffer is used to read and write to a memory buffer. It is normally " + "used with a QTextStream or a QDataStream. QBuffer has an associated " + "QByteArray which holds the buffer data. The size() of the buffer is " + "automatically adjusted as data is written.\n" + "The constructor QBuffer(QByteArray) creates a QBuffer using an existing " + "byte array. The byte array can also be set with setBuffer(). Writing to " + "the QBuffer will modify the original byte array because QByteArray is " + "explicitly shared.\n" + "Use open() to open the buffer before use and to set the mode (read-only, " + "write-only, etc.). close() closes the buffer. The buffer must be closed " + "before reopening or calling setBuffer().\n" + "A common way to use QBuffer is through QDataStream or QTextStream, which " + "have constructors that take a QBuffer parameter. For convenience, there " + "are also QDataStream and QTextStream constructors that take a QByteArray " + "parameter. These constructors create and open an internal QBuffer.\n" + "Note that QTextStream can also operate on a QString (a Unicode string); a " + "QBuffer cannot.\n" + "You can also use QBuffer directly through the standard QIODevice functions " + "readBlock(), writeBlock() readLine(), at(), getch(), putch() and ungetch().\n" + "See also QFile, QDataStream, QTextStream, QByteArray, Shared Classes, Collection " + "Classes and Input/Output and Networking."); +} + +void tst_QBuffer::writeBlock() +{ + QFETCH( QString, str ); + + QByteArray ba; + QBuffer buf( &ba ); + buf.open(QIODevice::ReadWrite); + QByteArray data = str.toLatin1(); + QCOMPARE(buf.write( data.constData(), data.size() ), qint64(data.size())); + + QCOMPARE(buf.data(), str.toLatin1()); +} + +void tst_QBuffer::seek() +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QCOMPARE(buffer.size(), qint64(0)); + QCOMPARE(buffer.pos(), qint64(0)); + const qint64 pos = 10; + QVERIFY(buffer.seek(pos)); + QCOMPARE(buffer.size(), pos); +} + +void tst_QBuffer::seekTest_data() +{ + writeBlock_data(); +} + +#define DO_VALID_SEEK(position) { \ + char c; \ + QVERIFY(buf.seek(qint64(position))); \ + QCOMPARE(buf.pos(), qint64(position)); \ + QVERIFY(buf.getChar(&c)); \ + QCOMPARE(QChar(c), str.at(qint64(position))); \ +} +#define DO_INVALID_SEEK(position) { \ + qint64 prev_pos = buf.pos(); \ + QVERIFY(!buf.seek(qint64(position))); \ + QCOMPARE(buf.pos(), prev_pos); /* position should not be changed */ \ +} + +void tst_QBuffer::seekTest() +{ + QFETCH(QString, str); + + QByteArray ba; + QBuffer buf(&ba); +#if 0 + QCOMPARE(buf.pos(), qint64(-1)); +#endif + buf.open(QIODevice::ReadWrite); + QCOMPARE(buf.pos(), qint64(0)); + + QByteArray data = str.toLatin1(); + QCOMPARE(buf.write( data.constData(), data.size() ), qint64(data.size())); + + QTest::ignoreMessage(QtWarningMsg, "QBuffer::seek: Invalid pos: -1"); + DO_INVALID_SEEK(-1); + + DO_VALID_SEEK(0); + DO_VALID_SEEK(str.size() - 1); + QVERIFY(buf.atEnd()); + DO_VALID_SEEK(str.size() / 2); + + // Special case: valid to seek one position past the buffer. + // Its then legal to write, but not read. + { + char c = 'a'; + QVERIFY(buf.seek(qint64(str.size()))); + QCOMPARE(buf.read(&c, qint64(1)), qint64(0)); + QCOMPARE(c, 'a'); + QCOMPARE(buf.write(&c, qint64(1)), qint64(1)); + } + + // Special case 2: seeking to an arbitrary position beyond the buffer auto-expands it + // (see Task 184730) + { + char c; + const int offset = 1; // any positive integer will do + const qint64 pos = buf.size() + offset; + QVERIFY(buf.seek(pos)); + QCOMPARE(buf.pos(), pos); + QVERIFY(!buf.getChar(&c)); + QVERIFY(buf.seek(pos - 1)); + QVERIFY(buf.getChar(&c)); + QCOMPARE(c, buf.data().at(pos - 1)); + QVERIFY(buf.seek(pos)); + QVERIFY(buf.putChar(c)); + } +} + +void tst_QBuffer::read_rawdata() +{ + static const unsigned char mydata[] = { + 0x01, 0x00, 0x03, 0x84, 0x78, 0x9c, 0x3b, 0x76, + 0xec, 0x18, 0xc3, 0x31, 0x0a, 0xf1, 0xcc, 0x99, + 0x6d, 0x5b + }; + + QByteArray data = QByteArray::fromRawData((const char *)mydata, sizeof(mydata)); + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + QDataStream in(&buffer); + quint8 ch; + for (int i = 0; i < (int)sizeof(mydata); ++i) { + QVERIFY(!buffer.atEnd()); + in >> ch; + QVERIFY(ch == (quint8)mydata[i]); + } + QVERIFY(buffer.atEnd()); +} + +void tst_QBuffer::isSequential() +{ + QBuffer buf; + QVERIFY(!buf.isSequential()); +} + +void tst_QBuffer::signalTest_data() +{ + QTest::addColumn<QByteArray>("sample"); + + QTest::newRow("empty") << QByteArray(); + QTest::newRow("size 1") << QByteArray("1"); + QTest::newRow("size 2") << QByteArray("11"); + QTest::newRow("size 100") << QByteArray(100, '1'); +} + +void tst_QBuffer::signalTest() +{ + QFETCH(QByteArray, sample); + + totalBytesWritten = 0; + + QBuffer buf; + buf.open(QIODevice::WriteOnly); + + buf.buffer().resize(sample.size() * 10); + connect(&buf, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(&buf, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64))); + + for (int i = 0; i < 10; ++i) { + gotReadyRead = false; + QCOMPARE(buf.write(sample), qint64(sample.size())); + if (sample.size() > 0) { + QTestEventLoop::instance().enterLoop(5); + if (QTestEventLoop::instance().timeout()) + QFAIL("Timed out when waiting for readyRead()"); + QCOMPARE(totalBytesWritten, qint64(sample.size() * (i + 1))); + QVERIFY(gotReadyRead); + } else { + QCOMPARE(totalBytesWritten, qint64(0)); + QVERIFY(!gotReadyRead); + } + } +} + +void tst_QBuffer::readyReadSlot() +{ + gotReadyRead = true; + QTestEventLoop::instance().exitLoop(); +} + +void tst_QBuffer::bytesWrittenSlot(qint64 written) +{ + totalBytesWritten += written; +} + +void tst_QBuffer::isClosedAfterClose() +{ + QBuffer buffer; + buffer.open(QBuffer::ReadOnly); + QVERIFY(buffer.isOpen()); + buffer.close(); + QVERIFY(!buffer.isOpen()); +} + +void tst_QBuffer::readLine_data() +{ + QTest::addColumn<QByteArray>("src"); + QTest::addColumn<int>("maxlen"); + QTest::addColumn<QByteArray>("expected"); + + QTest::newRow("1") << QByteArray("line1\nline2\n") << 1024 + << QByteArray("line1\n"); + QTest::newRow("2") << QByteArray("hi there") << 1024 + << QByteArray("hi there"); + QTest::newRow("3") << QByteArray("l\n") << 3 << QByteArray("l\n"); + QTest::newRow("4") << QByteArray("l\n") << 2 << QByteArray("l"); +} + +void tst_QBuffer::readLine() +{ + QFETCH(QByteArray, src); + QFETCH(int, maxlen); + QFETCH(QByteArray, expected); + + QBuffer buf; + buf.setBuffer(&src); + char *result = new char[maxlen + 1]; + result[maxlen] = '\0'; + + QVERIFY(buf.open(QIODevice::ReadOnly)); + + qint64 bytes_read = buf.readLine(result, maxlen); + + QCOMPARE(bytes_read, qint64(expected.size())); + QCOMPARE(QByteArray(result), expected); + + buf.close(); + delete[] result; + +} + +void tst_QBuffer::canReadLine_data() +{ + QTest::addColumn<QByteArray>("src"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("1") << QByteArray("no newline") << false; + QTest::newRow("2") << QByteArray("two \n lines\n") << true; + QTest::newRow("3") << QByteArray("\n") << true; + QTest::newRow("4") << QByteArray() << false; +} + +void tst_QBuffer::canReadLine() +{ + QFETCH(QByteArray, src); + QFETCH(bool, expected); + + QBuffer buf; + buf.setBuffer(&src); + QVERIFY(!buf.canReadLine()); + QVERIFY(buf.open(QIODevice::ReadOnly)); + QCOMPARE(buf.canReadLine(), expected); +} + +void tst_QBuffer::atEnd() +{ + QBuffer buffer; + buffer.open(QBuffer::Append); + buffer.write("heisann"); + buffer.close(); + + buffer.open(QBuffer::ReadOnly); + buffer.seek(buffer.size()); + char c; + QVERIFY(!buffer.getChar(&c)); + QCOMPARE(buffer.read(&c, 1), qint64(0)); +} + +void tst_QBuffer::readLineBoundaries() +{ + QByteArray line = "This is a line\n"; + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + while (buffer.size() < 16384) + buffer.write(line); + +/* + buffer.seek(0); + QFile out1("out1.txt"); + out1.open(QFile::WriteOnly); + out1.write(buffer.readAll()); + out1.close(); +*/ + buffer.seek(0); + + char c; + buffer.getChar(&c); + buffer.ungetChar(c); + + QFile out2("out2.txt"); + out2.open(QFile::WriteOnly); + while (!buffer.atEnd()) + out2.write(buffer.readLine()); + + out2.close(); + out2.remove(); +} + +void tst_QBuffer::writeAfterQByteArrayResize() +{ + QBuffer buffer; + QVERIFY(buffer.open(QIODevice::WriteOnly)); + + buffer.write(QByteArray().fill('a', 1000)); + QCOMPARE(buffer.buffer().size(), 1000); + + // resize the QByteArray behind QBuffer's back + buffer.buffer().clear(); + buffer.seek(0); + QCOMPARE(buffer.buffer().size(), 0); + + buffer.write(QByteArray().fill('b', 1000)); + QCOMPARE(buffer.buffer().size(), 1000); +} + +void tst_QBuffer::read_null() +{ + QByteArray buffer; + buffer.resize(32000); + for (int i = 0; i < buffer.size(); ++i) + buffer[i] = char(i & 0xff); + + QBuffer in(&buffer); + in.open(QIODevice::ReadOnly); + + QByteArray chunk; + + chunk.resize(16380); + in.read(chunk.data(), 16380); + + QCOMPARE(chunk, buffer.mid(0, chunk.size())); + + in.read(chunk.data(), 0); + + chunk.resize(8); + in.read(chunk.data(), chunk.size()); + + QCOMPARE(chunk, buffer.mid(16380, chunk.size())); +} + +QTEST_MAIN(tst_QBuffer) +#include "tst_qbuffer.moc" diff --git a/tests/auto/corelib/io/qdatastream/.gitignore b/tests/auto/corelib/io/qdatastream/.gitignore new file mode 100644 index 0000000000..cdcbaa591e --- /dev/null +++ b/tests/auto/corelib/io/qdatastream/.gitignore @@ -0,0 +1,2 @@ +datastream.tmp +tst_qdatastream diff --git a/tests/auto/corelib/io/qdatastream/datastream.q42 b/tests/auto/corelib/io/qdatastream/datastream.q42 Binary files differnew file mode 100644 index 0000000000..5c83f5c7fc --- /dev/null +++ b/tests/auto/corelib/io/qdatastream/datastream.q42 diff --git a/tests/auto/corelib/io/qdatastream/qdatastream.pro b/tests/auto/corelib/io/qdatastream/qdatastream.pro new file mode 100644 index 0000000000..5e503aea78 --- /dev/null +++ b/tests/auto/corelib/io/qdatastream/qdatastream.pro @@ -0,0 +1,20 @@ +load(qttest_p4) +SOURCES += tst_qdatastream.cpp + +wince*: { + addFiles.files = datastream.q42 + addFiles.path = . + DEPLOYMENT += addFiles + DEFINES += SRCDIR=\\\"\\\" +} else:symbian { + # SRCDIR defined in code in symbian + addFiles.files = datastream.q42 + addFiles.path = . + DEPLOYMENT += addFiles + TARGET.EPOCHEAPSIZE = 1000000 10000000 + TARGET.UID3 = 0xE0340001 + DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x","")) +}else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + diff --git a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp new file mode 100644 index 0000000000..e5a80d9bf3 --- /dev/null +++ b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp @@ -0,0 +1,3232 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtGui/QtGui> + +#if defined(Q_OS_SYMBIAN) +# define STRINGIFY(x) #x +# define TOSTRING(x) STRINGIFY(x) +# define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) "/" +#endif + +Q_DECLARE_METATYPE(QBitArray) +Q_DECLARE_METATYPE(qint64) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QDataStream : public QObject +{ +Q_OBJECT + +public: + tst_QDataStream(); + virtual ~tst_QDataStream(); + + void stream_data(int noOfElements); + +public slots: + void init(); + void cleanup(); + +private slots: + void getSetCheck(); + void stream_bool_data(); + void stream_bool(); + + void stream_QBool_data(); + void stream_QBool(); + + void stream_QBool_in_4_0(); + + void stream_QBitArray_data(); + void stream_QBitArray(); + + void stream_QBrush_data(); + void stream_QBrush(); + + void stream_QColor_data(); + void stream_QColor(); + + void stream_QByteArray_data(); + void stream_QByteArray(); + + void stream_QCursor_data(); + void stream_QCursor(); + + void stream_QDate_data(); + void stream_QDate(); + + void stream_QTime_data(); + void stream_QTime(); + + void stream_QDateTime_data(); + void stream_QDateTime(); + + void stream_QFont_data(); + void stream_QFont(); + + void stream_QImage_data(); + void stream_QImage(); + + void stream_QPen_data(); + void stream_QPen(); + + void stream_QPixmap_data(); + void stream_QPixmap(); + + void stream_QPoint_data(); + void stream_QPoint(); + + void stream_QRect_data(); + void stream_QRect(); + + void stream_QPolygon_data(); + void stream_QPolygon(); + + void stream_QRegion_data(); + void stream_QRegion(); + + void stream_QSize_data(); + void stream_QSize(); + + void stream_QString_data(); + void stream_QString(); + + void stream_QRegExp_data(); + void stream_QRegExp(); + + void stream_Map_data(); + void stream_Map(); + + void stream_Hash_data(); + void stream_Hash(); + + void stream_qint64_data(); + void stream_qint64(); + + void stream_QIcon_data(); + void stream_QIcon(); + + void stream_QEasingCurve_data(); + void stream_QEasingCurve(); + + void stream_atEnd_data(); + void stream_atEnd(); + + void stream_writeError(); + + void stream_QByteArray2(); + + void setVersion_data(); + void setVersion(); + + void skipRawData_data(); + void skipRawData(); + + void status_qint8_data(); + void status_qint8(); + void status_qint16_data(); + void status_qint16(); + void status_qint32_data(); + void status_qint32(); + void status_qint64_data(); + void status_qint64(); + + void status_float_data(); + void status_float(); + void status_double_data(); + void status_double(); + + void status_charptr_QByteArray_data(); + void status_charptr_QByteArray(); + + void status_QString_data(); + void status_QString(); + + void status_QBitArray_data(); + void status_QBitArray(); + + void status_QHash_QMap(); + + void status_QLinkedList_QList_QVector(); + + void streamToAndFromQByteArray(); + + void streamRealDataTypes(); + + void floatingPointPrecision(); + + void compatibility_Qt3(); + void compatibility_Qt2(); + +private: + void writebool(QDataStream *s); + void writeQBool(QDataStream *s); + void writeQBitArray(QDataStream *s); + void writeQBrush(QDataStream *s); + void writeQColor(QDataStream *s); + void writeQByteArray(QDataStream *s); + void writeQCursor(QDataStream *s); + void writeQWaitCursor(QDataStream *s); + void writeQDate(QDataStream *s); + void writeQTime(QDataStream *s); + void writeQDateTime(QDataStream *s); + void writeQFont(QDataStream *s); + void writeQImage(QDataStream *s); + void writeQPen(QDataStream *s); + void writeQPixmap(QDataStream *s); + void writeQPoint(QDataStream *s); + void writeQRect(QDataStream *s); + void writeQPolygon(QDataStream *s); + void writeQRegion(QDataStream *s); + void writeQSize(QDataStream *s); + void writeQString(QDataStream* dev); + void writeQRegExp(QDataStream* dev); + void writeMap(QDataStream* dev); + void writeHash(QDataStream* dev); + void writeqint64(QDataStream *s); + void writeQIcon(QDataStream *s); + void writeQEasingCurve(QDataStream *s); + + void readbool(QDataStream *s); + void readQBool(QDataStream *s); + void readQBitArray(QDataStream *s); + void readQBrush(QDataStream *s); + void readQColor(QDataStream *s); + void readQByteArray(QDataStream *s); + void readQCursor(QDataStream *s); + void readQDate(QDataStream *s); + void readQTime(QDataStream *s); + void readQDateTime(QDataStream *s); + void readQFont(QDataStream *s); + void readQImage(QDataStream *s); + void readQPen(QDataStream *s); + void readQPixmap(QDataStream *s); + void readQPoint(QDataStream *s); + void readQRect(QDataStream *s); + void readQPolygon(QDataStream *s); + void readQRegion(QDataStream *s); + void readQSize(QDataStream *s); + void readQString(QDataStream *s); + void readQRegExp(QDataStream *s); + void readMap(QDataStream *s); + void readHash(QDataStream *s); + void readqint64(QDataStream *s); + void readQIcon(QDataStream *s); + void readQEasingCurve(QDataStream *s); +}; + +static int NColorRoles[] = { + QPalette::NoRole, // No Version + QPalette::NoRole, // Qt_1_0 + QPalette::HighlightedText + 1, // Qt_2_0 + QPalette::HighlightedText + 1, // Qt_2_1 + QPalette::LinkVisited + 1, // Qt_3_0 + QPalette::HighlightedText + 1, // Qt_3_1 + QPalette::HighlightedText + 1, // Qt_3_3 + QPalette::HighlightedText + 1, // Qt_4_0, Qt_4_1 + QPalette::HighlightedText + 1, // Qt_4_2 + QPalette::AlternateBase + 1, // Qt_4_3 + QPalette::ToolTipText + 1, // Qt_4_4 + QPalette::ToolTipText + 1, // Qt_4_5 + QPalette::ToolTipText + 1, // Qt_4_6 + 0 // add the correct value for Qt_4_7 here later +}; + +// Testing get/set functions +void tst_QDataStream::getSetCheck() +{ + QDataStream obj1; + // QIODevice * QDataStream::device() + // void QDataStream::setDevice(QIODevice *) + QFile *var1 = new QFile; + obj1.setDevice(var1); + QCOMPARE((QIODevice *)var1, (QIODevice *)obj1.device()); + obj1.setDevice((QIODevice *)0); + QCOMPARE((QIODevice *)0, (QIODevice *)obj1.device()); + delete var1; + + // Status QDataStream::status() + // void QDataStream::setStatus(Status) + obj1.setStatus(QDataStream::Ok); + QCOMPARE(QDataStream::Ok, obj1.status()); + obj1.setStatus(QDataStream::ReadPastEnd); + QCOMPARE(QDataStream::ReadPastEnd, obj1.status()); + obj1.resetStatus(); + obj1.setStatus(QDataStream::ReadCorruptData); + QCOMPARE(QDataStream::ReadCorruptData, obj1.status()); +} + +tst_QDataStream::tst_QDataStream() +{ +} + +tst_QDataStream::~tst_QDataStream() +{ + QFile::remove(QLatin1String("qdatastream.out")); +} + +void tst_QDataStream::init() +{ +} + +void tst_QDataStream::cleanup() +{ +} + +static int dataIndex(const QString &tag) +{ + int pos = tag.lastIndexOf("_"); + if (pos >= 0) { + int ret = 0; + QString count = tag.mid(pos + 1); + bool ok; + ret = count.toInt(&ok); + if (ok) + return ret; + } + return -1; +} + +static const char * const devices[] = { + "file", + "bytearray", + "buffer", + 0 +}; + +/* + IMPORTANT. + In this testcase i follow a different approach than usual: I don't use the full power of + QtTestTable and QtTestData. This is done deliberately because QtTestData uses a QDataStream + itself to handle its data. So it would be a bit inapropriate to fully rely on QtTestData in this + testcase. + I do use QString in QtTestData because this is thouroughly tested in the selftest. +*/ +void tst_QDataStream::stream_data(int noOfElements) +{ + QTest::addColumn<QString>("device"); + QTest::addColumn<QString>("byteOrder"); + + for (int d=0; devices[d] != 0; d++) { + QString device = devices[d]; + for (int b=0; b<2; b++) { + QString byte_order = b == 0 ? "BigEndian" : "LittleEndian"; + + QString tag = device + "_" + byte_order; + for (int e=0; e<noOfElements; e++) { + QTest::newRow(qPrintable(tag + QString("_%1").arg(e))) << device << QString(byte_order); + } + } + } +} + +static const char* open_xpm[]={ +"16 13 6 1", +". c None", +"b c #ffff00", +"d c #000000", +"* c #999999", +"c c #cccccc", +"a c #ffffff", +"...*****........", +"..*aaaaa*.......", +".*abcbcba******.", +".*acbcbcaaaaaa*d", +".*abcbcbcbcbcb*d", +"*************b*d", +"*aaaaaaaaaa**c*d", +"*abcbcbcbcbbd**d", +".*abcbcbcbcbcd*d", +".*acbcbcbcbcbd*d", +"..*acbcbcbcbb*dd", +"..*************d", +"...ddddddddddddd"}; + +#define STREAM_IMPL(TYPE) \ + QFETCH(QString, device); \ + if (device == "bytearray") { \ + QByteArray ba; \ + QDataStream sout(&ba, QIODevice::WriteOnly); \ + write##TYPE(&sout); \ + QDataStream sin(&ba, QIODevice::ReadOnly); \ + read##TYPE(&sin); \ + } else if (device == "file") { \ + QString fileName = "qdatastream.out"; \ + QFile fOut(fileName); \ + QVERIFY(fOut.open(QIODevice::WriteOnly)); \ + QDataStream sout(&fOut); \ + write##TYPE(&sout); \ + fOut.close(); \ + QFile fIn(fileName); \ + QVERIFY(fIn.open(QIODevice::ReadOnly)); \ + QDataStream sin(&fIn); \ + read##TYPE(&sin); \ + fIn.close(); \ + } else if (device == "buffer") { \ + QByteArray ba(10000, '\0'); \ + QBuffer bOut(&ba); \ + bOut.open(QIODevice::WriteOnly); \ + QDataStream sout(&bOut); \ + write##TYPE(&sout); \ + bOut.close(); \ + QBuffer bIn(&ba); \ + bIn.open(QIODevice::ReadOnly); \ + QDataStream sin(&bIn); \ + read##TYPE(&sin); \ + bIn.close(); \ + } + +// ************************************ + +static QString QStringData(int index) +{ + switch (index) { + case 0: return QString(); + case 1: return QString(""); + case 2: return QString("A"); + case 3: return QString("ABCDE FGHI"); + case 4: return QString("This is a long string"); + case 5: return QString("And again a string with a \nCRLF"); + case 6: return QString("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRESTUVWXYZ 1234567890 ~`!@#$%^&*()_-+={[}]|\\:;\"'<,>.?/"); + } + return QString("foo"); +} +#define MAX_QSTRING_DATA 7 + +void tst_QDataStream::stream_QString_data() +{ + stream_data(MAX_QSTRING_DATA); +} + +void tst_QDataStream::stream_QString() +{ + STREAM_IMPL(QString); +} + +void tst_QDataStream::writeQString(QDataStream* s) +{ + QString test(QStringData(dataIndex(QTest::currentDataTag()))); + *s << test; + *s << QString("Her er det noe tekst"); + *s << test; + *s << QString(); + *s << test; + *s << QString(""); + *s << test; + *s << QString("nonempty"); + *s << test; +} + +void tst_QDataStream::readQString(QDataStream *s) +{ + QString S; + QString test(QStringData(dataIndex(QTest::currentDataTag()))); + + *s >> S; + QCOMPARE(S, test); + *s >> S; + QCOMPARE(S, QString("Her er det noe tekst")); + *s >> S; + QCOMPARE(S, test); + *s >> S; + QVERIFY(S.isNull()); + *s >> S; + QCOMPARE(S, test); + *s >> S; + QVERIFY(S.isEmpty()); + *s >> S; + QCOMPARE(S, test); + *s >> S; + QCOMPARE(S, QString("nonempty")); + *s >> S; + QCOMPARE(S, test); +} + +// ************************************ + +static QRegExp QRegExpData(int index) +{ + switch (index) { + case 0: return QRegExp(); + case 1: return QRegExp(""); + case 2: return QRegExp("A", Qt::CaseInsensitive); + case 3: return QRegExp("ABCDE FGHI", Qt::CaseSensitive, QRegExp::Wildcard); + case 4: return QRegExp("This is a long string", Qt::CaseInsensitive, QRegExp::FixedString); + case 5: return QRegExp("And again a string with a \nCRLF", Qt::CaseInsensitive, QRegExp::RegExp); + case 6: + { + QRegExp rx("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRESTUVWXYZ 1234567890 ~`!@#$%^&*()_-+={[}]|\\:;\"'<,>.?/"); + rx.setMinimal(true); + return rx; + } + } + return QRegExp("foo"); +} +#define MAX_QREGEXP_DATA 7 + +void tst_QDataStream::stream_QRegExp_data() +{ + stream_data(MAX_QREGEXP_DATA); +} + +void tst_QDataStream::stream_QRegExp() +{ + STREAM_IMPL(QRegExp); +} + +void tst_QDataStream::writeQRegExp(QDataStream* s) +{ + QRegExp test(QRegExpData(dataIndex(QTest::currentDataTag()))); + *s << test; + *s << QString("Her er det noe tekst"); + *s << test; + *s << QString("nonempty"); + *s << test; + *s << QVariant(test); +} + +void tst_QDataStream::readQRegExp(QDataStream *s) +{ + QRegExp R; + QString S; + QVariant V; + QRegExp test(QRegExpData(dataIndex(QTest::currentDataTag()))); + + *s >> R; + QCOMPARE(R, test); + *s >> S; + QCOMPARE(S, QString("Her er det noe tekst")); + *s >> R; + QCOMPARE(R, test); + *s >> S; + QCOMPARE(S, QString("nonempty")); + *s >> R; + QCOMPARE(R, test); + *s >> V; + QVERIFY(V.type() == QVariant::RegExp); + QCOMPARE(V.toRegExp(), test); +} + +// ************************************ + +typedef QMap<int, QString> Map; + +static Map MapData(int index) +{ + Map map; + + switch (index) { + case 0: + default: + break; + case 1: + map.insert(1, "a"); + map.insert(2, "bbb"); + map.insert(3, "cccccc"); + break; + case 2: + map.insert(1, "a"); + map.insert(2, "one"); + map.insertMulti(2, "two"); + map.insertMulti(2, "three"); + map.insert(3, "cccccc"); + } + return map; +} +#define MAX_MAP_DATA 3 + +void tst_QDataStream::stream_Map_data() +{ + stream_data(MAX_MAP_DATA); +} + +void tst_QDataStream::stream_Map() +{ + STREAM_IMPL(Map); +} + +void tst_QDataStream::writeMap(QDataStream* s) +{ + Map test(MapData(dataIndex(QTest::currentDataTag()))); + *s << test; + *s << test; +} + +void tst_QDataStream::readMap(QDataStream *s) +{ + Map S; + Map test(MapData(dataIndex(QTest::currentDataTag()))); + + *s >> S; + QCOMPARE(S, test); + *s >> S; + QCOMPARE(S, test); +} + +// ************************************ + +typedef QHash<int, QString> Hash; + +static Hash HashData(int index) +{ + Hash map; + + switch (index) { + case 0: + default: + break; + case 1: + map.insert(1, "a"); + map.insert(2, "bbb"); + map.insert(3, "cccccc"); + break; + case 2: + map.insert(1, "a"); + map.insert(2, "one"); + map.insertMulti(2, "two"); + map.insertMulti(2, "three"); + map.insert(3, "cccccc"); + } + return map; +} +#define MAX_HASH_DATA 3 + +void tst_QDataStream::stream_Hash_data() +{ + stream_data(MAX_HASH_DATA); +} + +void tst_QDataStream::stream_Hash() +{ + STREAM_IMPL(Hash); +} + +void tst_QDataStream::writeHash(QDataStream* s) +{ + Hash test(HashData(dataIndex(QTest::currentDataTag()))); + *s << test; + *s << test; +} + +void tst_QDataStream::readHash(QDataStream *s) +{ + Hash S; + Hash test(HashData(dataIndex(QTest::currentDataTag()))); + + *s >> S; + QCOMPARE(S, test); + *s >> S; + QCOMPARE(S, test); +} + +// ************************************ + +static QEasingCurve QEasingCurveData(int index) +{ + QEasingCurve easing; + + switch (index) { + case 0: + default: + break; + case 1: + easing.setType(QEasingCurve::Linear); + break; + case 2: + easing.setType(QEasingCurve::OutCubic); + break; + case 3: + easing.setType(QEasingCurve::InOutSine); + break; + case 4: + easing.setType(QEasingCurve::InOutElastic); + easing.setPeriod(1.5); + easing.setAmplitude(2.0); + break; + case 5: + easing.setType(QEasingCurve::OutInBack); + break; + case 6: + easing.setType(QEasingCurve::OutCurve); + break; + case 7: + easing.setType(QEasingCurve::InOutBack); + easing.setOvershoot(0.5); + break; + } + return easing; +} +#define MAX_EASING_DATA 8 + +void tst_QDataStream::stream_QEasingCurve_data() +{ + stream_data(MAX_EASING_DATA); +} + +void tst_QDataStream::stream_QEasingCurve() +{ + STREAM_IMPL(QEasingCurve); +} + +void tst_QDataStream::writeQEasingCurve(QDataStream* s) +{ + QEasingCurve test(QEasingCurveData(dataIndex(QTest::currentDataTag()))); + *s << test; +} + +void tst_QDataStream::readQEasingCurve(QDataStream *s) +{ + QEasingCurve S; + QEasingCurve expected(QEasingCurveData(dataIndex(QTest::currentDataTag()))); + + *s >> S; + QCOMPARE(S, expected); +} + +// ************************************ + +// contains some quint64 testing as well + +#define MAX_qint64_DATA 4 + +static qint64 qint64Data(int index) +{ + switch (index) { + case 0: return qint64(0); + case 1: return qint64(1); + case 2: return qint64(-1); + case 3: return qint64(1) << 40; + case MAX_qint64_DATA: return -(qint64(1) << 40); + } + + return -1; +} + +void tst_QDataStream::stream_qint64_data() +{ + stream_data(MAX_qint64_DATA+1); +} + +void tst_QDataStream::stream_qint64() +{ + STREAM_IMPL(qint64); +} + +void tst_QDataStream::writeqint64(QDataStream* s) +{ + qint64 test = qint64Data(dataIndex(QTest::currentDataTag())); + *s << test; + *s << int(1); + *s << (quint64)test; +} + +void tst_QDataStream::readqint64(QDataStream *s) +{ + qint64 test = qint64Data(dataIndex(QTest::currentDataTag())); + qint64 i64; + quint64 ui64; + int i; + *s >> i64; + QCOMPARE(i64, test); + *s >> i; + QCOMPARE(i, int(1)); + *s >> ui64; + QCOMPARE(ui64, (quint64)test); +} + +// ************************************ + +static bool boolData(int index) +{ + switch (index) { + case 0: return true; + case 1: return false; + case 2: return bool(2); + case 3: return bool(-1); + case 4: return bool(127); + } + + return false; +} + +void tst_QDataStream::stream_bool_data() +{ + stream_data(5); +} + +void tst_QDataStream::stream_bool() +{ + STREAM_IMPL(bool); +} + +void tst_QDataStream::writebool(QDataStream *s) +{ + bool d1 = boolData(dataIndex(QTest::currentDataTag())); + *s << d1; +} + +void tst_QDataStream::readbool(QDataStream *s) +{ + bool expected = boolData(dataIndex(QTest::currentDataTag())); + + bool d1; + *s >> d1; + QVERIFY(d1 == expected); +} + +// ************************************ + +static QBool QBoolData(int index) +{ + switch (index) { + case 0: return QBool(true); + case 1: return QBool(false); + case 2: return QBool(bool(2)); + case 3: return QBool(bool(-1)); + case 4: return QBool(bool(127)); + } + + return QBool(false); +} + +void tst_QDataStream::stream_QBool_data() +{ + stream_data(5); +} + +void tst_QDataStream::stream_QBool() +{ + STREAM_IMPL(QBool); +} + +void tst_QDataStream::writeQBool(QDataStream *s) +{ + QBool d1 = QBoolData(dataIndex(QTest::currentDataTag())); + *s << d1; +} + +void tst_QDataStream::readQBool(QDataStream *s) +{ + QBool expected = QBoolData(dataIndex(QTest::currentDataTag())); + + bool d1 = true; + *s >> d1; + QVERIFY(d1 == expected); +} + +void tst_QDataStream::stream_QBool_in_4_0() +{ + QByteArray byteArray; + QDataStream out(&byteArray, QIODevice::WriteOnly); + + QString str("ABC"); + out << str.contains('A') << str.contains('Z'); + + QCOMPARE(byteArray.size(), 2); +} + +// ************************************ + +static void QBitArrayData(QBitArray *b, int index) +{ + QString filler = ""; + switch (index) { + case 0: filler = ""; break; + case 1: filler = ""; break; + case 2: filler = "0"; break; + case 3: filler = "1"; break; + case 4: filler = "0000"; break; + case 5: filler = "0001"; break; + case 6: filler = "0010"; break; + case 7: filler = "0100"; break; + case 8: filler = "1000"; break; + case 9: filler = "1111"; break; + case 10: filler = "00000000"; break; + case 11: filler = "00000001"; break; + case 12: filler = "11111111"; break; + case 13: filler = "000000001"; break; + case 14: filler = "000000000001"; break; + case 15: filler = "0000000000000001"; break; + case 16: filler = "0101010101010101010101010101010101010101010101010101010101010101"; break; + case 17: filler = "1010101010101010101010101010101010101010101010101010101010101010"; break; + case 18: filler = "1111111111111111111111111111111111111111111111111111111111111111"; break; + } + + b->resize(filler.length()); + b->fill(0); // reset all bits to zero + + for (int i = 0; i < filler.length(); ++i) { + if (filler.at(i) == '1') + b->setBit(i, TRUE); + } +} + +void tst_QDataStream::stream_QBitArray_data() +{ + stream_data(19); +} + +void tst_QDataStream::stream_QBitArray() +{ + STREAM_IMPL(QBitArray); +} + +void tst_QDataStream::writeQBitArray(QDataStream *s) +{ + QBitArray d1; + QBitArrayData(&d1, dataIndex(QTest::currentDataTag())); + *s << d1; +} + +void tst_QDataStream::readQBitArray(QDataStream *s) +{ + QBitArray expected; + QBitArrayData(&expected, dataIndex(QTest::currentDataTag())); + + QBitArray d1; + *s >> d1; + QVERIFY(d1 == expected); +} + +// ************************************ + +static QBrush qBrushData(int index) +{ + switch (index) { + case 0: return QBrush(Qt::NoBrush); + case 1: return QBrush(Qt::SolidPattern); + case 2: return QBrush(Qt::Dense7Pattern); + case 3: return QBrush(Qt::red, Qt::NoBrush); + case 4: return QBrush(Qt::green, Qt::SolidPattern); + case 5: return QBrush(Qt::blue, Qt::Dense7Pattern); + case 6: + { + QPixmap pm(open_xpm); + QBrush custom(Qt::black, pm); + return custom; + } + case 7: + QLinearGradient gradient(QPoint(2.718, 3.142), QPoint(3.1337, 42)); + gradient.setCoordinateMode(QGradient::ObjectBoundingMode); + gradient.setSpread(QGradient::ReflectSpread); + gradient.setInterpolationMode(QGradient::ComponentInterpolation); + gradient.setColorAt(0.2, Qt::red); + gradient.setColorAt(0.6, Qt::transparent); + gradient.setColorAt(0.8, Qt::blue); + return QBrush(gradient); + } + + return QBrush(Qt::NoBrush); +} + +void tst_QDataStream::stream_QBrush_data() +{ + stream_data(8); +} + +void tst_QDataStream::stream_QBrush() +{ + if (QString(QTest::currentDataTag()).endsWith("6")) + QSKIP("Custom brushes don't seem to be supported with QDataStream", SkipSingle); + + STREAM_IMPL(QBrush); +} + +void tst_QDataStream::writeQBrush(QDataStream *s) +{ + QBrush brush = qBrushData(dataIndex(QTest::currentDataTag())); + *s << brush; +} + +void tst_QDataStream::readQBrush(QDataStream *s) +{ + QBrush d2; + *s >> d2; + + QBrush brush = qBrushData(dataIndex(QTest::currentDataTag())); + QVERIFY(d2 == brush); +} + +// ************************************ + +static QColor QColorData(int index) +{ + switch (index) { + case 0: return QColor(0,0,0); + case 1: return QColor(0,0,0); + case 2: return QColor(0,0,0); + case 3: return QColor(0,0,0); + case 4: return QColor(0,0,0); + case 5: return QColor(0,0,0); + case 6: return QColor(0,0,0); + case 7: return QColor(0,0,0); + } + + return QColor(0,0,0); +} + +void tst_QDataStream::stream_QColor_data() +{ + stream_data(8); +} + +void tst_QDataStream::stream_QColor() +{ + STREAM_IMPL(QColor); +} + +void tst_QDataStream::writeQColor(QDataStream *s) +{ + QColor d3(QColorData(dataIndex(QTest::currentDataTag()))); + *s << d3; +} + +void tst_QDataStream::readQColor(QDataStream *s) +{ + QColor test(QColorData(dataIndex(QTest::currentDataTag()))); + QColor d3; + *s >> d3; + QVERIFY(d3 == test); +} + + +// ************************************ + +static QByteArray qByteArrayData(int index) +{ + switch (index) { + case 0: return QByteArray(); + case 1: return QByteArray(""); + case 2: return QByteArray("foo"); + case 3: return QByteArray("foo bar"); + case 4: return QByteArray("two\nlines"); + case 5: return QByteArray("ABCDEFG"); + case 6: return QByteArray("baec zxv 123"); // kept for nostalgic reasons + case 7: return QByteArray("jbc;UBC;jd clhdbcahd vcbd vgdv dhvb laifv kadf jkhfbvljd khd lhvjh "); + } + + return QByteArray("foo"); +} + +void tst_QDataStream::stream_QByteArray_data() +{ + stream_data(8); +} + +void tst_QDataStream::stream_QByteArray() +{ + STREAM_IMPL(QByteArray); +} + +void tst_QDataStream::writeQByteArray(QDataStream *s) +{ + QByteArray d4(qByteArrayData(dataIndex(QTest::currentDataTag()))); + *s << d4; +} + +void tst_QDataStream::readQByteArray(QDataStream *s) +{ + QByteArray test(qByteArrayData(dataIndex(QTest::currentDataTag()))); + QByteArray d4; + *s >> d4; + QCOMPARE(d4, test); +} + +// ************************************ +#ifndef QT_NO_CURSOR +static QCursor qCursorData(int index) +{ + switch (index) { + case 0: return QCursor(Qt::ArrowCursor); + case 1: return QCursor(Qt::WaitCursor); + case 2: return QCursor(Qt::BitmapCursor); + case 3: return QCursor(Qt::BlankCursor); + case 4: return QCursor(Qt::BlankCursor); + case 5: return QCursor(QPixmap(open_xpm), 1, 1); + case 6: { QPixmap pm(open_xpm); return QCursor(QBitmap(pm), pm.mask(), 3, 4); } + case 7: return QCursor(QPixmap(open_xpm), -1, 5); + case 8: return QCursor(QPixmap(open_xpm), 5, -1); + } + + return QCursor(); +} +#endif + +void tst_QDataStream::stream_QCursor_data() +{ +#ifndef QT_NO_CURSOR + stream_data(9); +#endif +} + +void tst_QDataStream::stream_QCursor() +{ +#ifndef QT_NO_CURSOR + STREAM_IMPL(QCursor); +#endif +} + +void tst_QDataStream::writeQCursor(QDataStream *s) +{ +#ifndef QT_NO_CURSOR + QCursor d5(qCursorData(dataIndex(QTest::currentDataTag()))); + *s << d5; +#endif +} + +void tst_QDataStream::readQCursor(QDataStream *s) +{ +#ifndef QT_NO_CURSOR + QCursor test(qCursorData(dataIndex(QTest::currentDataTag()))); + QCursor d5; + *s >> d5; + + QVERIFY(d5.shape() == test.shape()); //## lacks operator== + QVERIFY(d5.hotSpot() == test.hotSpot()); + QVERIFY((d5.bitmap() != 0 && test.bitmap() != 0) || (d5.bitmap() == 0 && test.bitmap() == 0)); + if (d5.bitmap() != 0) + QVERIFY(pixmapsAreEqual(d5.bitmap(), test.bitmap())); + QVERIFY((d5.mask() != 0 && test.mask() != 0) || (d5.mask() == 0 && test.mask() == 0)); + if (d5.mask() != 0) + QVERIFY(pixmapsAreEqual(d5.mask(), test.mask())); +#endif +} + +// ************************************ + +static QDate qDateData(int index) +{ + switch (index) { + case 0: return QDate(1752, 9, 14); // the first valid date + case 1: return QDate(1900, 1, 1); + case 2: return QDate(1976, 4, 5); + case 3: return QDate(1960, 5, 27); + case 4: return QDate(1999, 12, 31); // w2k effects? + case 5: return QDate(2000, 1, 1); + case 6: return QDate(2050, 1, 1);// test some values far in the future too + case 7: return QDate(3001, 12, 31); + case 8: return QDate(4002, 1, 1); + case 9: return QDate(4003, 12, 31); + case 10: return QDate(5004, 1, 1); + case 11: return QDate(5005, 12, 31); + case 12: return QDate(6006, 1, 1); + case 13: return QDate(6007, 12, 31); + case 14: return QDate(7008, 1, 1); + case 15: return QDate(7009, 12, 31); + } + return QDate(); +} +#define MAX_QDATE_DATA 16 + +void tst_QDataStream::stream_QDate_data() +{ + stream_data(MAX_QDATE_DATA); +} + +void tst_QDataStream::stream_QDate() +{ + STREAM_IMPL(QDate); +} + +void tst_QDataStream::writeQDate(QDataStream *s) +{ + QDate d6(qDateData(dataIndex(QTest::currentDataTag()))); + *s << d6; +} + +void tst_QDataStream::readQDate(QDataStream *s) +{ + QDate test(qDateData(dataIndex(QTest::currentDataTag()))); + QDate d6; + *s >> d6; + QVERIFY(d6 == test); +} + +// ************************************ + +static QTime qTimeData(int index) +{ + switch (index) { + case 0 : return QTime(0, 0, 0, 0); + case 1 : return QTime(0, 0, 0, 1); + case 2 : return QTime(0, 0, 0, 99); + case 3 : return QTime(0, 0, 0, 100); + case 4 : return QTime(0, 0, 0, 999); + case 5 : return QTime(0, 0, 1, 0); + case 6 : return QTime(0, 0, 1, 1); + case 7 : return QTime(0, 0, 1, 99); + case 8 : return QTime(0, 0, 1, 100); + case 9 : return QTime(0, 0, 1, 999); + case 10: return QTime(0, 0, 59, 0); + case 11: return QTime(0, 0, 59, 1); + case 12: return QTime(0, 0, 59, 99); + case 13: return QTime(0, 0, 59, 100); + case 14: return QTime(0, 0, 59, 999); + case 15: return QTime(0, 59, 0, 0); + case 16: return QTime(0, 59, 0, 1); + case 17: return QTime(0, 59, 0, 99); + case 18: return QTime(0, 59, 0, 100); + case 19: return QTime(0, 59, 0, 999); + case 20: return QTime(0, 59, 1, 0); + case 21: return QTime(0, 59, 1, 1); + case 22: return QTime(0, 59, 1, 99); + case 23: return QTime(0, 59, 1, 100); + case 24: return QTime(0, 59, 1, 999); + case 25: return QTime(0, 59, 59, 0); + case 26: return QTime(0, 59, 59, 1); + case 27: return QTime(0, 59, 59, 99); + case 28: return QTime(0, 59, 59, 100); + case 29: return QTime(0, 59, 59, 999); + case 30: return QTime(23, 0, 0, 0); + case 31: return QTime(23, 0, 0, 1); + case 32: return QTime(23, 0, 0, 99); + case 33: return QTime(23, 0, 0, 100); + case 34: return QTime(23, 0, 0, 999); + case 35: return QTime(23, 0, 1, 0); + case 36: return QTime(23, 0, 1, 1); + case 37: return QTime(23, 0, 1, 99); + case 38: return QTime(23, 0, 1, 100); + case 39: return QTime(23, 0, 1, 999); + case 40: return QTime(23, 0, 59, 0); + case 41: return QTime(23, 0, 59, 1); + case 42: return QTime(23, 0, 59, 99); + case 43: return QTime(23, 0, 59, 100); + case 44: return QTime(23, 0, 59, 999); + case 45: return QTime(23, 59, 0, 0); + case 46: return QTime(23, 59, 0, 1); + case 47: return QTime(23, 59, 0, 99); + case 48: return QTime(23, 59, 0, 100); + case 49: return QTime(23, 59, 0, 999); + case 50: return QTime(23, 59, 1, 0); + case 51: return QTime(23, 59, 1, 1); + case 52: return QTime(23, 59, 1, 99); + case 53: return QTime(23, 59, 1, 100); + case 54: return QTime(23, 59, 1, 999); + case 55: return QTime(23, 59, 59, 0); + case 56: return QTime(23, 59, 59, 1); + case 57: return QTime(23, 59, 59, 99); + case 58: return QTime(23, 59, 59, 100); + case 59: return QTime(23, 59, 59, 999); + } + return QTime(0, 0, 0); +} +#define MAX_QTIME_DATA 60 + +void tst_QDataStream::stream_QTime_data() +{ + stream_data(MAX_QTIME_DATA); +} + +void tst_QDataStream::stream_QTime() +{ + STREAM_IMPL(QTime); +} + +void tst_QDataStream::writeQTime(QDataStream *s) +{ + QTime d7 = qTimeData(dataIndex(QTest::currentDataTag())); + *s << d7; +} + +void tst_QDataStream::readQTime(QDataStream *s) +{ + QTime test = qTimeData(dataIndex(QTest::currentDataTag())); + QTime d7; + *s >> d7; + QVERIFY(d7 == test); +} + +// ************************************ + +static QDateTime qDateTimeData(int index) +{ + switch (index) { + case 0: return QDateTime(QDate(1900, 1, 1), QTime(0,0,0,0)); + case 1: return QDateTime(QDate(1900, 1, 2), QTime(1,1,1,1)); + case 2: return QDateTime(QDate(1900, 1, 3), QTime(12,0,0,0)); + case 3: return QDateTime(QDate(1900, 1, 4), QTime(23,59,59,999)); + case 4: return QDateTime(QDate(1999, 1, 1), QTime(0,0,0,0)); + case 5: return QDateTime(QDate(1999, 1, 2), QTime(1,1,1,1)); + case 6: return QDateTime(QDate(1999, 1, 3), QTime(12,0,0,0)); + case 7: return QDateTime(QDate(1999, 1, 4), QTime(23,59,59,999)); + case 8: return QDateTime(QDate(2000, 1, 1), QTime(0,0,0,0)); + case 9: return QDateTime(QDate(2000, 1, 2), QTime(1,1,1,1)); + case 10: return QDateTime(QDate(2000, 1, 3), QTime(12,0,0,0)); + case 11: return QDateTime(QDate(2000, 1, 4), QTime(23,59,59,999)); + case 12: return QDateTime(QDate(2000, 12, 31), QTime(0,0,0,0)); + case 13: return QDateTime(QDate(2000, 12, 31), QTime(1,1,1,1)); + case 14: return QDateTime(QDate(2000, 12, 31), QTime(12,0,0,0)); + case 15: return QDateTime(QDate(2000, 12, 31), QTime(23,59,59,999)); + } + return QDateTime(QDate(1900, 1, 1), QTime(0,0,0)); +} +#define MAX_QDATETIME_DATA 16 + +void tst_QDataStream::stream_QDateTime_data() +{ + stream_data(MAX_QDATETIME_DATA); +} + +void tst_QDataStream::stream_QDateTime() +{ + STREAM_IMPL(QDateTime); +} + +void tst_QDataStream::writeQDateTime(QDataStream *s) +{ + QDateTime dt(qDateTimeData(dataIndex(QTest::currentDataTag()))); + *s << dt; +} + +void tst_QDataStream::readQDateTime(QDataStream *s) +{ + QDateTime test(qDateTimeData(dataIndex(QTest::currentDataTag()))); + QDateTime d8; + *s >> d8; + QVERIFY(d8 == test); +} + +// ************************************ + +static QFont qFontData(int index) +{ + switch (index) { + case 0: return QFont("Courier", 20, QFont::Bold, TRUE); + case 1: return QFont("Courier", 18, QFont::Bold, FALSE); + case 2: return QFont("Courier", 16, QFont::Light, TRUE); + case 3: return QFont("Courier", 14, QFont::Normal, FALSE); + case 4: return QFont("Courier", 12, QFont::DemiBold, TRUE); + case 5: return QFont("Courier", 10, QFont::Black, FALSE); + case 6: + { + QFont f("Helvetica", 10, QFont::Normal, FALSE); + f.setPixelSize(2); + f.setUnderline(FALSE); + f.setStrikeOut(FALSE); + f.setFixedPitch(FALSE); + return f; + } + case 7: + { + QFont f("Helvetica", 10, QFont::Bold, FALSE); + f.setPixelSize(4); + f.setUnderline(TRUE); + f.setStrikeOut(FALSE); + f.setFixedPitch(FALSE); + return f; + } + case 8: + { + QFont f("Helvetica", 10, QFont::Light, FALSE); + f.setPixelSize(6); + f.setUnderline(FALSE); + f.setStrikeOut(TRUE); + f.setFixedPitch(FALSE); + return f; + } + case 9: + { + QFont f("Helvetica", 10, QFont::DemiBold, FALSE); + f.setPixelSize(8); + f.setUnderline(FALSE); + f.setStrikeOut(FALSE); + f.setFixedPitch(TRUE); + return f; + } + case 10: + { + QFont f("Helvetica", 10, QFont::Black, FALSE); + f.setPixelSize(10); + f.setUnderline(TRUE); + f.setStrikeOut(TRUE); + f.setFixedPitch(FALSE); + return f; + } + case 11: + { + QFont f("Helvetica", 10, QFont::Normal, TRUE); + f.setPixelSize(12); + f.setUnderline(FALSE); + f.setStrikeOut(TRUE); + f.setFixedPitch(TRUE); + return f; + } + case 12: + { + QFont f("Helvetica", 10, QFont::Bold, TRUE); + f.setPixelSize(14); + f.setUnderline(TRUE); + f.setStrikeOut(TRUE); + f.setFixedPitch(TRUE); + return f; + } + case 13: + { + QFont f("Helvetica", 10, QFont::Bold, TRUE); + f.setStretch(200); + return f; + } + } + return QFont("Courier", 18, QFont::Bold, TRUE); +} +#define MAX_QFONT_DATA 14 + +void tst_QDataStream::stream_QFont_data() +{ + stream_data(MAX_QFONT_DATA); +} + +void tst_QDataStream::stream_QFont() +{ + STREAM_IMPL(QFont); +} + +void tst_QDataStream::writeQFont(QDataStream *s) +{ + QFont d9(qFontData(dataIndex(QTest::currentDataTag()))); + *s << d9; +} + +void tst_QDataStream::readQFont(QDataStream *s) +{ + QFont test(qFontData(dataIndex(QTest::currentDataTag()))); + QFont d9; + *s >> d9; + + // maybe a bit overkill ... + QCOMPARE(d9.family(), test.family()); + QCOMPARE(d9.pointSize(), test.pointSize()); + QCOMPARE(d9.pixelSize(), test.pixelSize()); + QCOMPARE(d9.weight(), test.weight()); + QCOMPARE(d9.bold(), test.bold()); + QCOMPARE(d9.italic(), test.italic()); + QCOMPARE(d9.underline(), test.underline()); + QCOMPARE(d9.overline(), test.overline()); + QCOMPARE(d9.strikeOut(), test.strikeOut()); + QCOMPARE(d9.fixedPitch(), test.fixedPitch()); + QCOMPARE(d9.styleHint(), test.styleHint()); + QCOMPARE(d9.toString(), test.toString()); + + QCOMPARE(d9, test); +} + +// ************************************ + +void tst_QDataStream::stream_QImage_data() +{ + stream_data(1); +} + +void tst_QDataStream::stream_QImage() +{ + STREAM_IMPL(QImage); +} + +void tst_QDataStream::writeQImage(QDataStream *s) +{ + QImage d12(open_xpm); + *s << d12; +} + +void tst_QDataStream::readQImage(QDataStream *s) +{ + QImage ref(open_xpm); + + QImage d12; + *s >> d12; + QVERIFY(d12 == ref); + + // do some extra neurotic tests + QVERIFY(d12.size() == ref.size()); + QVERIFY(d12.isNull() == ref.isNull()); + QVERIFY(d12.width() == ref.width()); + QVERIFY(d12.height() == ref.height()); + QVERIFY(d12.depth() == ref.depth()); + QVERIFY(d12.colorCount() == ref.colorCount()); + QVERIFY(d12.hasAlphaChannel() == ref.hasAlphaChannel()); + +// ################ Bug : ref and orig has ff in alpha; readback has 0 +// ### (Was like this in 1.44 as well) +// +// for(int i = 0; i < d12.height(); i++) +// for(int j = 0; j < d12.width(); j++) +// if (d12.pixel(j, i) != ref.pixel(j, i)) +// qDebug("Feil %i %i", j, i); +// +} + +// ************************************ + +static QPen qPenData(int index) +{ + switch (index) { + case 0: + { + QPen p(Qt::blue, 0, Qt::NoPen); + p.setCapStyle(Qt::FlatCap); + p.setJoinStyle(Qt::MiterJoin); + return p; + } + case 1: + { + QPen p(Qt::red, 1, Qt::SolidLine); + p.setCapStyle(Qt::SquareCap); + p.setJoinStyle(Qt::BevelJoin); + return p; + } + case 2: + { + QPen p(Qt::red, 4, Qt::DashDotDotLine); + p.setCapStyle(Qt::RoundCap); + p.setJoinStyle(Qt::RoundJoin); + return p; + } + case 3: + { + QPen p(Qt::blue, 12, Qt::NoPen); + p.setCapStyle(Qt::FlatCap); + p.setJoinStyle(Qt::RoundJoin); + return p; + } + case 4: + { + QPen p(Qt::red, 99, Qt::SolidLine); + p.setCapStyle(Qt::SquareCap); + p.setJoinStyle(Qt::MiterJoin); + return p; + } + case 5: + { + QPen p(Qt::red, 255, Qt::DashDotLine); + p.setCapStyle(Qt::RoundCap); + p.setJoinStyle(Qt::BevelJoin); + return p; + } + case 6: + { + QPen p(Qt::red, 256, Qt::DashDotLine); + p.setCapStyle(Qt::RoundCap); + p.setJoinStyle(Qt::BevelJoin); + return p; + } + case 7: + { + QPen p(Qt::red, 0.25, Qt::DashDotLine); + p.setCapStyle(Qt::RoundCap); + p.setJoinStyle(Qt::BevelJoin); + return p; + } + } + + return QPen(); +} +#define MAX_QPEN_DATA 8 + +void tst_QDataStream::stream_QPen_data() +{ + stream_data(MAX_QPEN_DATA); +} + +void tst_QDataStream::stream_QPen() +{ + /* + edba: + data6 fails because the width is clipped to a byte (max 255) in the datastream. + This limitation is not documented. + */ + + STREAM_IMPL(QPen); +} + +void tst_QDataStream::writeQPen(QDataStream *s) +{ + QPen d15(qPenData(dataIndex(QTest::currentDataTag()))); + *s << d15; +} + +void tst_QDataStream::readQPen(QDataStream *s) +{ + QPen origPen(qPenData(dataIndex(QTest::currentDataTag()))); + QPen d15; + *s >> d15; + QCOMPARE(d15.style(), origPen.style()); + QCOMPARE(d15.width(), origPen.width()); + QCOMPARE(d15.color(), origPen.color()); + QVERIFY(d15.capStyle() == origPen.capStyle()); + QVERIFY(d15.joinStyle() == origPen.joinStyle()); + QVERIFY(d15 == origPen); +} + +// ************************************ + +// pixmap testing is currently limited to one pixmap only. +// +void tst_QDataStream::stream_QPixmap_data() +{ +#ifndef Q_OS_WINCE + stream_data(1); +#endif +} + +void tst_QDataStream::stream_QPixmap() +{ +#ifdef Q_OS_WINCE + QSKIP("Test depends on more memory than available on Qt/CE", SkipAll); +#endif + STREAM_IMPL(QPixmap); +} + +void tst_QDataStream::stream_QIcon_data() +{ +#ifndef Q_OS_WINCE + stream_data(1); +#endif +} + +void tst_QDataStream::stream_QIcon() +{ +#ifdef Q_OS_WINCE + QSKIP("Test depends on more memory than available on Qt/CE", SkipAll); +#endif + STREAM_IMPL(QIcon); +} + +void tst_QDataStream::writeQPixmap(QDataStream *s) +{ + QPixmap d16(open_xpm); + *s << d16; +} + +void tst_QDataStream::readQPixmap(QDataStream *s) +{ + QPixmap pm(open_xpm); + QPixmap d16; + *s >> d16; + QVERIFY(!d16.isNull() && !pm.isNull()); + QVERIFY(d16.width() == pm.width()); + QVERIFY(d16.height() == pm.height()); + QVERIFY(d16.size() == pm.size()); + QVERIFY(d16.rect() == pm.rect()); + QVERIFY(d16.depth() == pm.depth()); +} + +void tst_QDataStream::writeQIcon(QDataStream *s) +{ + QPixmap pm(open_xpm); + QIcon d16(pm); + *s << d16; +} + +void tst_QDataStream::readQIcon(QDataStream *s) +{ + QPixmap pm(open_xpm); + QIcon icon(pm); + QIcon d16; + *s >> d16; + QVERIFY(!d16.isNull() && !icon.isNull()); + QCOMPARE(d16.pixmap(100), pm); +} + +// ************************************ + +QPoint qPointData(int index) +{ + switch (index) { + case 0: return QPoint(0, 0); + case 1: return QPoint(-1, 0); + case 2: return QPoint(0, -1); + case 3: return QPoint(1, 0); + case 4: return QPoint(0, 1); + case 5: return QPoint(-1, -1); + case 6: return QPoint(1, 1); + case 7: return QPoint(255, 255); + case 8: return QPoint(256, 256); + case 9: return QPoint(-254, -254); + case 10: return QPoint(-255, -255); + } + + return QPoint(); +} +#define MAX_QPOINT_DATA 11 + + +void tst_QDataStream::stream_QPoint_data() +{ + stream_data(MAX_QPOINT_DATA); +} + +void tst_QDataStream::stream_QPoint() +{ + STREAM_IMPL(QPoint); +} + +void tst_QDataStream::writeQPoint(QDataStream *s) +{ + QPoint d17(qPointData(dataIndex(QTest::currentDataTag()))); + *s << d17; + + QPointF d17f = d17; + *s << d17f; +} + +void tst_QDataStream::readQPoint(QDataStream *s) +{ + QPoint ref(qPointData(dataIndex(QTest::currentDataTag()))); + QPoint d17; + *s >> d17; + QVERIFY(d17 == ref); + + QPointF d17f; + *s >> d17f; + QVERIFY(d17f == QPointF(ref)); +} + +// ************************************ + +static QRect qRectData(int index) +{ + switch (index) { + case 0: return QRect(0, 0, 0, 0); + case 1: return QRect(1, 1, 1, 1); + case 2: return QRect(1, 2, 3, 4); + case 3: return QRect(-1, -1, -1, -1); + case 4: return QRect(-1, -2, -3, -4); + case 5: return QRect(255, -5, 256, -6); + case 6: return QRect(-7, 255, -8, 256); + case 7: return QRect(9, -255, 10, -255); + case 8: return QRect(-255, 11, -255, 12); + case 9: return QRect(256, 512, 1024, 2048); + case 10: return QRect(-256, -512, -1024, -2048); + } + return QRect(); +} +#define MAX_QRECT_DATA 11 + +void tst_QDataStream::stream_QRect_data() +{ + stream_data(MAX_QRECT_DATA); +} + +void tst_QDataStream::stream_QRect() +{ + STREAM_IMPL(QRect); +} + +void tst_QDataStream::writeQRect(QDataStream *s) +{ + QRect d18(qRectData(dataIndex(QTest::currentDataTag()))); + *s << d18; + + QRectF d18f(d18); + *s << d18f; +} + +void tst_QDataStream::readQRect(QDataStream *s) +{ + QRect ref(qRectData(dataIndex(QTest::currentDataTag()))); + QRect d18; + *s >> d18; + QVERIFY(d18 == ref); + + QRectF d18f; + *s >> d18f; + QVERIFY(d18f == QRectF(ref)); +} + +// ************************************ + +static QPolygon qPolygonData(int index) +{ + QPoint p0(0, 0); + QPoint p1(1, 1); + QPoint p2(-1, -1); + QPoint p3(1, -1); + QPoint p4(-1, 1); + QPoint p5(0, 255); + QPoint p6(0, 256); + QPoint p7(0, 1024); + QPoint p8(255, 0); + QPoint p9(256, 0); + QPoint p10(1024, 0); + QPoint p11(345, 678); + QPoint p12(23456, 99999); + QPoint p13(-99998, -34567); + QPoint p14(45678, -99999); + + switch (index) { + case 0: + return QPolygon(0); + case 1: + { + QPolygon p(1); + p.setPoint(0, p0); + return p; + } + case 2: + { + QPolygon p(1); + p.setPoint(0, p5); + return p; + } + case 3: + { + QPolygon p(1); + p.setPoint(0, p12); + return p; + } + case 4: + { + QPolygon p(3); + p.setPoint(0, p1); + p.setPoint(1, p10); + p.setPoint(2, p13); + return p; + } + case 5: + { + QPolygon p(6); + p.setPoint(0, p2); + p.setPoint(1, p11); + p.setPoint(2, p14); + return p; + } + case 6: + { + QPolygon p(15); + p.setPoint(0, p0); + p.setPoint(1, p1); + p.setPoint(2, p2); + p.setPoint(3, p3); + p.setPoint(4, p4); + p.setPoint(5, p5); + p.setPoint(6, p6); + p.setPoint(7, p7); + p.setPoint(8, p8); + p.setPoint(9, p9); + p.setPoint(10, p10); + p.setPoint(11, p11); + p.setPoint(12, p12); + p.setPoint(13, p13); + p.setPoint(14, p14); + return p; + } + } + return QRect(); +} +#define MAX_QPOINTARRAY_DATA 7 + +void tst_QDataStream::stream_QPolygon_data() +{ + stream_data(1); +} + +void tst_QDataStream::stream_QPolygon() +{ + STREAM_IMPL(QPolygon); +} + +void tst_QDataStream::writeQPolygon(QDataStream *s) +{ + QPolygon d19(qPolygonData(dataIndex(QTest::currentDataTag()))); + *s << d19; + + QPolygonF d19f(d19); + *s << d19f; +} + +void tst_QDataStream::readQPolygon(QDataStream *s) +{ + QPolygon ref(qPolygonData(dataIndex(QTest::currentDataTag()))); + QPolygon d19; + *s >> d19; + QVERIFY(d19 == ref); + + QPolygonF d19f; + *s >> d19f; + QVERIFY(d19f == QPolygonF(ref)); +} + +// ************************************ + +static QRegion qRegionData(int index) +{ + switch (index) { + case 0: return QRegion(0, 0, 0, 0, QRegion::Rectangle); + case 1: + { + QRegion r(1, 2, 300, 400, QRegion::Rectangle); + if (r != QRegion(1, 2, 300, 400, QRegion::Rectangle)) + qDebug("Error creating a region"); + return r; + } + case 2: return QRegion(100, 100, 1024, 768, QRegion::Rectangle); + case 3: return QRegion(-100, -100, 1024, 1024, QRegion::Rectangle); + case 4: return QRegion(100, -100, 2048, 4096, QRegion::Rectangle); + case 5: return QRegion(-100, 100, 4096, 2048, QRegion::Rectangle); + case 6: return QRegion(0, 0, 0, 0, QRegion::Ellipse); +#if defined(Q_OS_SYMBIAN) || (!defined(Q_OS_UNIX) && !defined(Q_OS_WINCE)) // all our Unix platforms use X regions. + case 7: return QRegion(1, 2, 300, 400, QRegion::Ellipse); + case 8: return QRegion(100, 100, 1024, 768, QRegion::Ellipse); + case 9: return QRegion(-100, -100, 1024, 1024, QRegion::Ellipse); + case 10: return QRegion(100, -100, 2048, 4096, QRegion::Ellipse); + case 11: return QRegion(-100, 100, 4096, 2048, QRegion::Ellipse); + // simplest X11 case that fails: + case 12: return QRegion(0, 0, 3, 3, QRegion::Ellipse); +#else + case 7: + qWarning("Skipping streaming of elliptical regions on embedded, Mac OS X, and X11;" + " our pointarray stuff is not that great at approximating."); +#endif + } + return QRegion(); +} +#define MAX_QREGION_DATA 12 + +void tst_QDataStream::stream_QRegion_data() +{ + stream_data(MAX_QREGION_DATA); +} + +void tst_QDataStream::stream_QRegion() +{ + STREAM_IMPL(QRegion); +} + +void tst_QDataStream::writeQRegion(QDataStream *s) +{ + QRegion r(qRegionData(dataIndex(QTest::currentDataTag()))); + *s << r; +} + +void tst_QDataStream::readQRegion(QDataStream *s) +{ + QRegion ref(qRegionData(dataIndex(QTest::currentDataTag()))); + QRegion r; + *s >> r; + QVERIFY(r == ref); +} + +// ************************************ + +static QSize qSizeData(int index) +{ + switch (index) { + case 0: return QSize(0, 0); + case 1: return QSize(-1, 0); + case 2: return QSize(0, -1); + case 3: return QSize(1, 0); + case 4: return QSize(0, 1); + case 5: return QSize(-1, -1); + case 6: return QSize(1, 1); + case 7: return QSize(255, 255); + case 8: return QSize(256, 256); + case 9: return QSize(-254, -254); + case 10: return QSize(-255, -255); + } + return QSize(); +} +#define MAX_QSIZE_DATA 11 + +void tst_QDataStream::stream_QSize_data() +{ + stream_data(MAX_QSIZE_DATA); +} + +void tst_QDataStream::stream_QSize() +{ + STREAM_IMPL(QSize); +} + +void tst_QDataStream::writeQSize(QDataStream *s) +{ + QSize d21(qSizeData(dataIndex(QTest::currentDataTag()))); + *s << d21; + + QSizeF d21f(d21); + *s << d21f; +} + +void tst_QDataStream::readQSize(QDataStream *s) +{ + QSize ref(qSizeData(dataIndex(QTest::currentDataTag()))); + QSize d21; + *s >> d21; + QVERIFY(d21 == ref); + + QSizeF d21f; + *s >> d21f; + QVERIFY(d21f == QSizeF(ref)); +} + +// *********************** atEnd ****************************** + +void tst_QDataStream::stream_atEnd_data() +{ + stream_data(MAX_QSTRING_DATA); +} + +void tst_QDataStream::stream_atEnd() +{ + QFETCH(QString, device); + if (device == "bytearray") { + QByteArray ba; + QDataStream sout(&ba, QIODevice::WriteOnly); + writeQString(&sout); + + QDataStream sin(&ba, QIODevice::ReadOnly); + readQString(&sin); + QVERIFY(sin.atEnd()); + } else if (device == "file") { + QString fileName = "qdatastream.out"; + QFile fOut(fileName); + QVERIFY(fOut.open(QIODevice::WriteOnly)); + QDataStream sout(&fOut); + writeQString(&sout); + fOut.close(); + + QFile fIn(fileName); + QVERIFY(fIn.open(QIODevice::ReadOnly)); + QDataStream sin(&fIn); + readQString(&sin); + QVERIFY(sin.atEnd()); + fIn.close(); + } else if (device == "buffer") { + { + QByteArray ba(0); + QBuffer bOut(&ba); + bOut.open(QIODevice::WriteOnly); + QDataStream sout(&bOut); + writeQString(&sout); + bOut.close(); + + QBuffer bIn(&ba); + bIn.open(QIODevice::ReadOnly); + QDataStream sin(&bIn); + readQString(&sin); + QVERIFY(sin.atEnd()); + bIn.close(); + } + + // Do the same test again, but this time with an initial size for the bytearray. + { + QByteArray ba(10000, '\0'); + QBuffer bOut(&ba); + bOut.open(QIODevice::WriteOnly | QIODevice::Truncate); + QDataStream sout(&bOut); + writeQString(&sout); + bOut.close(); + + QBuffer bIn(&ba); + bIn.open(QIODevice::ReadOnly); + QDataStream sin(&bIn); + readQString(&sin); + QVERIFY(sin.atEnd()); + bIn.close(); + } + } +} + +class FakeBuffer : public QBuffer +{ +protected: + qint64 writeData(const char *c, qint64 i) { return m_lock ? 0 : QBuffer::writeData(c, i); } +public: + FakeBuffer(bool locked = false) : m_lock(locked) {} + void setLocked(bool locked) { m_lock = locked; } +private: + bool m_lock; +}; + +#define TEST_WRITE_ERROR(op) \ + { \ + FakeBuffer fb(false); \ + QVERIFY(fb.open(QBuffer::ReadWrite)); \ + QDataStream fs(&fb); \ + fs.writeRawData("hello", 5); \ + /* first write some initial content */ \ + QCOMPARE(fs.status(), QDataStream::Ok); \ + QCOMPARE(fb.data(), QByteArray("hello")); \ + /* then test that writing can cause an error */ \ + fb.setLocked(true); \ + fs op; \ + QCOMPARE(fs.status(), QDataStream::WriteFailed); \ + QCOMPARE(fb.data(), QByteArray("hello")); \ + /* finally test that writing after an error doesn't change the stream any more */ \ + fb.setLocked(false); \ + fs op; \ + QCOMPARE(fs.status(), QDataStream::WriteFailed); \ + QCOMPARE(fb.data(), QByteArray("hello")); \ + } + +void tst_QDataStream::stream_writeError() +{ + TEST_WRITE_ERROR(<< true) + TEST_WRITE_ERROR(<< (qint8)1) + TEST_WRITE_ERROR(<< (quint8)1) + TEST_WRITE_ERROR(<< (qint16)1) + TEST_WRITE_ERROR(<< (quint16)1) + TEST_WRITE_ERROR(<< (qint32)1) + TEST_WRITE_ERROR(<< (quint32)1) + TEST_WRITE_ERROR(<< (qint64)1) + TEST_WRITE_ERROR(<< (quint64)1) + TEST_WRITE_ERROR(<< "hello") + TEST_WRITE_ERROR(<< (float)1.0) + TEST_WRITE_ERROR(<< (double)1.0) + TEST_WRITE_ERROR(.writeRawData("test", 4)) +} + +void tst_QDataStream::stream_QByteArray2() +{ + QByteArray ba; + { + QDataStream s(&ba, QIODevice::WriteOnly); + s << QByteArray("hallo"); + s << QByteArray(""); + s << QByteArray(); + } + + { + QDataStream s(&ba, QIODevice::ReadOnly); + QByteArray res; + s >> res; + QCOMPARE(res, QByteArray("hallo")); + s >> res; + QCOMPARE(res, QByteArray("")); + QVERIFY(res.isEmpty()); + QVERIFY(!res.isNull()); + s >> res; + QCOMPARE(res, QByteArray()); + QVERIFY(res.isEmpty()); + QVERIFY(res.isNull()); + } +} + +void tst_QDataStream::setVersion_data() +{ + QTest::addColumn<int>("vers"); + QDataStream latest; + + for (int vers = 1; vers <= latest.version(); ++vers) + QTest::newRow(qPrintable(QString("v_%1").arg(vers))) << vers; +} + +void tst_QDataStream::setVersion() +{ + QDataStream latest; + QFETCH(int, vers); + + /* + Test QKeySequence. + */ + QByteArray ba1; + { + QDataStream out(&ba1, QIODevice::WriteOnly); + out.setVersion(vers); + out << QKeySequence(Qt::Key_A) << QKeySequence(Qt::Key_B, Qt::Key_C) + << (quint32)0xDEADBEEF; + } + { + QKeySequence keyseq1, keyseq2; + quint32 deadbeef; + QDataStream in(&ba1, QIODevice::ReadOnly); + in.setVersion(vers); + in >> keyseq1 >> keyseq2 >> deadbeef; + QVERIFY(keyseq1 == QKeySequence(Qt::Key_A)); + if (vers >= 5) { + QVERIFY(keyseq2 == QKeySequence(Qt::Key_B, Qt::Key_C)); + } else { + QVERIFY(keyseq2 == QKeySequence(Qt::Key_B)); + } + QVERIFY(deadbeef == 0xDEADBEEF); + } + + /* + Test QPalette. + */ + + // revise the test if new color roles or color groups are added + QVERIFY(QPalette::NColorRoles == QPalette::ToolTipText + 1); + QVERIFY(QPalette::NColorGroups == 3); + + QByteArray ba2; + QPalette pal1, pal2; + for (int grp = 0; grp < (int)QPalette::NColorGroups; ++grp) { + for (int role = 0; role < (int)QPalette::NColorRoles; ++role) { + // random stuff + pal1.setColor((QPalette::ColorGroup)grp, (QPalette::ColorRole)role, + QColor(grp * 13, 255 - grp, role)); + pal2.setColor((QPalette::ColorGroup)grp, (QPalette::ColorRole)role, + QColor(role * 11, 254 - role, grp)); + } + } + + { + QDataStream out(&ba2, QIODevice::WriteOnly); + out.setVersion(vers); + out << pal1 << pal2 << (quint32)0xCAFEBABE; + } + { + QPalette inPal1, inPal2; + quint32 cafebabe; + QDataStream in(&ba2, QIODevice::ReadOnly); + in.setVersion(vers); + in >> inPal1 >> inPal2; + in >> cafebabe; + + QCOMPARE(cafebabe, 0xCAFEBABE); + + QCOMPARE(NColorRoles[latest.version()], (int)QPalette::NColorRoles); //if this fails you need to update the NColorRoles array + + if (vers == 1) { + for (int grp = 0; grp < (int)QPalette::NColorGroups; ++grp) { + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Foreground) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Foreground)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Background) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Background)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Light) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Light)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Dark) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Dark)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Mid) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Mid)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Text) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Text)); + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Base) + == inPal1.color((QPalette::ColorGroup)grp, QPalette::Base)); + + QVERIFY(pal1.color((QPalette::ColorGroup)grp, QPalette::Midlight) + != inPal1.color((QPalette::ColorGroup)grp, QPalette::Midlight)); + } + } else { + if (NColorRoles[vers] < QPalette::NColorRoles) { + QVERIFY(pal1 != inPal1); + QVERIFY(pal2 != inPal2); + + for (int grp = 0; grp < (int)QPalette::NColorGroups; ++grp) { + for (int i = NColorRoles[vers]; i < QPalette::NColorRoles; ++i) { + inPal1.setColor((QPalette::ColorGroup)grp, (QPalette::ColorRole)i, + pal1.color((QPalette::ColorGroup)grp, (QPalette::ColorRole)i)); + inPal2.setColor((QPalette::ColorGroup)grp, (QPalette::ColorRole)i, + pal2.color((QPalette::ColorGroup)grp, (QPalette::ColorRole)i)); + } + } + } + QVERIFY(pal1 == inPal1); + QVERIFY(pal2 == inPal2); + } + } +} + +class SequentialBuffer : public QBuffer +{ +public: + SequentialBuffer(QByteArray *data) : QBuffer(data) { offset = 0; } + + bool isSequential() const { return true; } + bool seek(qint64 pos) { offset = pos; return QBuffer::seek(pos); } + qint64 pos() const { return qint64(offset); } + +protected: + qint64 readData(char *data, qint64 maxSize) + { + qint64 ret = QBuffer::readData(data, maxSize); + offset += ret; + return ret; + } + +private: + int offset; +}; + +void tst_QDataStream::skipRawData_data() +{ + QTest::addColumn<QString>("deviceType"); + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<int>("read"); + QTest::addColumn<int>("skip"); + QTest::addColumn<int>("skipped"); + QTest::addColumn<char>("expect"); + + QByteArray bigData; + bigData.fill('a', 20000); + bigData[10001] = 'x'; + + QTest::newRow("1") << QString("sequential") << QByteArray("abcdefghij") << 3 << 6 << 6 << 'j'; + QTest::newRow("2") << QString("random-access") << QByteArray("abcdefghij") << 3 << 6 << 6 << 'j'; + QTest::newRow("3") << QString("sequential") << bigData << 1 << 10000 << 10000 << 'x'; + QTest::newRow("4") << QString("random-access") << bigData << 1 << 10000 << 10000 << 'x'; + QTest::newRow("5") << QString("sequential") << bigData << 1 << 20000 << 19999 << '\0'; + QTest::newRow("6") << QString("random-access") << bigData << 1 << 20000 << 19999 << '\0'; +} + +void tst_QDataStream::skipRawData() +{ + QFETCH(QString, deviceType); + QFETCH(QByteArray, data); + QFETCH(int, read); + QFETCH(int, skip); + QFETCH(int, skipped); + QFETCH(char, expect); + qint8 dummy; + + QIODevice *dev = 0; + if (deviceType == "sequential") { + dev = new SequentialBuffer(&data); + } else if (deviceType == "random-access") { + dev = new QBuffer(&data); + } + QVERIFY(dev); + dev->open(QIODevice::ReadOnly); + + QDataStream in(dev); + for (int i = 0; i < read; ++i) + in >> dummy; + + QCOMPARE(in.skipRawData(skip), skipped); + in >> dummy; + QCOMPARE((char)dummy, expect); + + delete dev; +} + +#define TEST_qint(T, UT) \ + void tst_QDataStream::status_##T() \ + { \ + QFETCH(QByteArray, bigEndianData); \ + QFETCH(QByteArray, littleEndianData); \ + QFETCH(int, expectedStatus); \ + QFETCH(qint64, expectedValue); \ + \ + { \ + QDataStream stream(&bigEndianData, QIODevice::ReadOnly); \ + T i; \ + stream >> i; \ + QCOMPARE((int) stream.status(), expectedStatus); \ + QCOMPARE(i, (T) expectedValue); \ + } \ + { \ + QDataStream stream(&bigEndianData, QIODevice::ReadOnly); \ + UT i; \ + stream >> i; \ + QCOMPARE((int) stream.status(), expectedStatus); \ + QCOMPARE((T) i, (T) expectedValue); \ + } \ + { \ + QDataStream stream(&littleEndianData, QIODevice::ReadOnly); \ + stream.setByteOrder(QDataStream::LittleEndian); \ + T i; \ + stream >> i; \ + QCOMPARE((int) stream.status(), expectedStatus); \ + QCOMPARE(i, (T) expectedValue); \ + } \ + { \ + QDataStream stream(&littleEndianData, QIODevice::ReadOnly); \ + stream.setByteOrder(QDataStream::LittleEndian); \ + UT i; \ + stream >> i; \ + QCOMPARE((int) stream.status(), expectedStatus); \ + QCOMPARE((T) i, (T) expectedValue); \ + } \ + } + +#define TEST_FLOAT(T) \ + void tst_QDataStream::status_##T() \ + { \ + QFETCH(QByteArray, bigEndianData); \ + QFETCH(QByteArray, littleEndianData); \ + QFETCH(int, expectedStatus); \ + QFETCH(double, expectedValue); \ + \ + QDataStream::FloatingPointPrecision prec = sizeof(T) == sizeof(double) ? QDataStream::DoublePrecision : QDataStream::SinglePrecision; \ + \ + { \ + QDataStream stream(&bigEndianData, QIODevice::ReadOnly); \ + stream.setFloatingPointPrecision(prec); \ + T i; \ + stream >> i; \ + QCOMPARE((int) stream.status(), expectedStatus); \ + QCOMPARE((float) i, (float) expectedValue); \ + } \ + { \ + QDataStream stream(&littleEndianData, QIODevice::ReadOnly); \ + stream.setByteOrder(QDataStream::LittleEndian); \ + stream.setFloatingPointPrecision(prec); \ + T i; \ + stream >> i; \ + QCOMPARE((int) stream.status(), expectedStatus); \ + QCOMPARE((float) i, (float) expectedValue); \ + } \ + } + +void tst_QDataStream::status_qint8_data() +{ + QTest::addColumn<QByteArray>("bigEndianData"); + QTest::addColumn<QByteArray>("littleEndianData"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<qint64>("expectedValue"); + + // ok + QTest::newRow("0") << QByteArray(1, '\x0') << QByteArray(1, '\x0') << (int) QDataStream::Ok << qint64(0); + QTest::newRow("-1") << QByteArray(1, '\xff') << QByteArray(1, '\xff') << (int) QDataStream::Ok << qint64(-1); + QTest::newRow("1") << QByteArray(1, '\x01') << QByteArray(1, '\x01') << (int) QDataStream::Ok << qint64(1); + QTest::newRow("37") << QByteArray(1, '\x25') << QByteArray(1, '\x25') << (int) QDataStream::Ok << qint64(37); + QTest::newRow("37j") << QByteArray("\x25j") << QByteArray("\x25j") << (int) QDataStream::Ok << qint64(37); + + // past end + QTest::newRow("empty") << QByteArray() << QByteArray() << (int) QDataStream::ReadPastEnd << qint64(0); +} + +TEST_qint(qint8, quint8) + +void tst_QDataStream::status_qint16_data() +{ + QTest::addColumn<QByteArray>("bigEndianData"); + QTest::addColumn<QByteArray>("littleEndianData"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<qint64>("expectedValue"); + + // ok + QTest::newRow("0") << QByteArray(2, '\x0') << QByteArray(2, '\x0') << (int) QDataStream::Ok << qint64(0); + QTest::newRow("-1") << QByteArray("\xff\xff", 2) << QByteArray("\xff\xff", 2) << (int) QDataStream::Ok << qint64(-1); + QTest::newRow("1") << QByteArray("\x00\x01", 2) << QByteArray("\x01\x00", 2) << (int) QDataStream::Ok << qint64(1); + QTest::newRow("37") << QByteArray("\x00\x25", 2) << QByteArray("\x25\x00", 2) << (int) QDataStream::Ok << qint64(37); + QTest::newRow("37j") << QByteArray("\x00\x25j", 3) << QByteArray("\x25\x00j", 3) << (int) QDataStream::Ok << qint64(37); + QTest::newRow("0x1234") << QByteArray("\x12\x34", 2) << QByteArray("\x34\x12", 2) << (int) QDataStream::Ok << qint64(0x1234); + + // past end + QTest::newRow("empty") << QByteArray() << QByteArray() << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 1") << QByteArray("", 1) << QByteArray("", 1) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 2") << QByteArray("\x25", 1) << QByteArray("\x25", 1) << (int) QDataStream::ReadPastEnd << qint64(0); +} + +TEST_qint(qint16, quint16) + +void tst_QDataStream::status_qint32_data() +{ + QTest::addColumn<QByteArray>("bigEndianData"); + QTest::addColumn<QByteArray>("littleEndianData"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<qint64>("expectedValue"); + + // ok + QTest::newRow("0") << QByteArray(4, '\x0') << QByteArray(4, '\x0') << (int) QDataStream::Ok << qint64(0); + QTest::newRow("-1") << QByteArray("\xff\xff\xff\xff", 4) << QByteArray("\xff\xff\xff\xff", 4) << (int) QDataStream::Ok << qint64(-1); + QTest::newRow("1") << QByteArray("\x00\x00\x00\x01", 4) << QByteArray("\x01\x00\x00\x00", 4) << (int) QDataStream::Ok << qint64(1); + QTest::newRow("37") << QByteArray("\x00\x00\x00\x25", 4) << QByteArray("\x25\x00\x00\x00", 4) << (int) QDataStream::Ok << qint64(37); + QTest::newRow("37j") << QByteArray("\x00\x00\x00\x25j", 5) << QByteArray("\x25\x00\x00\x00j", 5) << (int) QDataStream::Ok << qint64(37); + QTest::newRow("0x12345678") << QByteArray("\x12\x34\x56\x78", 4) << QByteArray("\x78\x56\x34\x12", 4) << (int) QDataStream::Ok << qint64(0x12345678); + + // past end + QTest::newRow("empty") << QByteArray() << QByteArray() << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 1") << QByteArray("", 1) << QByteArray("", 1) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 2") << QByteArray("\x25", 1) << QByteArray("\x25", 1) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 3") << QByteArray("11", 2) << QByteArray("11", 2) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 4") << QByteArray("111", 3) << QByteArray("111", 3) << (int) QDataStream::ReadPastEnd << qint64(0); +} + +TEST_qint(qint32, quint32) + +void tst_QDataStream::status_qint64_data() +{ + QTest::addColumn<QByteArray>("bigEndianData"); + QTest::addColumn<QByteArray>("littleEndianData"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<qint64>("expectedValue"); + + // ok + QTest::newRow("0") << QByteArray(8, '\x0') << QByteArray(8, '\x0') << (int) QDataStream::Ok << qint64(0); + QTest::newRow("-1") << QByteArray("\xff\xff\xff\xff\xff\xff\xff\xff", 8) << QByteArray("\xff\xff\xff\xff\xff\xff\xff\xff", 8) << (int) QDataStream::Ok << qint64(-1); + QTest::newRow("1") << QByteArray("\x00\x00\x00\x00\x00\x00\x00\x01", 8) << QByteArray("\x01\x00\x00\x00\x00\x00\x00\x00", 8) << (int) QDataStream::Ok << qint64(1); + QTest::newRow("37") << QByteArray("\x00\x00\x00\x00\x00\x00\x00\x25", 8) << QByteArray("\x25\x00\x00\x00\x00\x00\x00\x00", 8) << (int) QDataStream::Ok << qint64(37); + QTest::newRow("37j") << QByteArray("\x00\x00\x00\x00\x00\x00\x00\x25j", 9) << QByteArray("\x25\x00\x00\x00\x00\x00\x00\x00j", 9) << (int) QDataStream::Ok << qint64(37); + QTest::newRow("0x123456789ABCDEF0") << QByteArray("\x12\x34\x56\x78\x9a\xbc\xde\xf0", 8) << QByteArray("\xf0\xde\xbc\x9a\x78\x56\x34\x12", 8) << (int) QDataStream::Ok << (qint64)Q_INT64_C(0x123456789ABCDEF0); + + // past end + QTest::newRow("empty") << QByteArray() << QByteArray() << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 1") << QByteArray("", 1) << QByteArray("", 1) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 2") << QByteArray("\x25", 1) << QByteArray("\x25", 1) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 3") << QByteArray("11", 2) << QByteArray("11", 2) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 4") << QByteArray("111", 3) << QByteArray("111", 3) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 5") << QByteArray("1111", 4) << QByteArray("1111", 4) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 6") << QByteArray("11111", 5) << QByteArray("11111", 5) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 7") << QByteArray("111111", 6) << QByteArray("111111", 6) << (int) QDataStream::ReadPastEnd << qint64(0); + QTest::newRow("end 8") << QByteArray("1111111", 7) << QByteArray("1111111", 7) << (int) QDataStream::ReadPastEnd << qint64(0); +} + +TEST_qint(qint64, quint64) + +void tst_QDataStream::status_float_data() +{ + QTest::addColumn<QByteArray>("bigEndianData"); + QTest::addColumn<QByteArray>("littleEndianData"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<double>("expectedValue"); + + // ok + QTest::newRow("0") << QByteArray(4, '\0') << QByteArray(4, '\0') << (int) QDataStream::Ok << (double) 0.0; + QTest::newRow("-1") << QByteArray("\xbf\x80\x00\x00", 4) << QByteArray("\x00\x00\x80\xbf", 4) << (int) QDataStream::Ok << (double) -1; + QTest::newRow("1") << QByteArray("\x3f\x80\x00\x00", 4) << QByteArray("\x00\x00\x80\x3f", 4) << (int) QDataStream::Ok << (double) 1; + QTest::newRow("37") << QByteArray("\x42\x14\x00\x00", 4) << QByteArray("\x00\x00\x14\x42", 4) << (int) QDataStream::Ok << (double) 37; + QTest::newRow("37j") << QByteArray("\x42\x14\x00\x00j", 5) << QByteArray("\x00\x00\x14\x42j", 5) << (int) QDataStream::Ok << (double) 37; + QTest::newRow("3.14") << QByteArray("\x40\x48\xf5\xc3", 4) << QByteArray("\xc3\xf5\x48\x40", 4) << (int) QDataStream::Ok << (double) 3.14; + + // past end + QTest::newRow("empty") << QByteArray() << QByteArray() << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 1") << QByteArray("", 1) << QByteArray("", 1) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 2") << QByteArray("\x25", 1) << QByteArray("\x25", 1) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 3") << QByteArray("11", 2) << QByteArray("11", 2) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 4") << QByteArray("111", 3) << QByteArray("111", 3) << (int) QDataStream::ReadPastEnd << double(0); +} + +TEST_FLOAT(float) + +void tst_QDataStream::status_double_data() +{ + QTest::addColumn<QByteArray>("bigEndianData"); + QTest::addColumn<QByteArray>("littleEndianData"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<double>("expectedValue"); + + // ok + QTest::newRow("0") << QByteArray("\x00\x00\x00\x00\x00\x00\x00\x00", 8) << QByteArray("\x00\x00\x00\x00\x00\x00\x00\x00", 8) << (int) QDataStream::Ok << (double) 0; + QTest::newRow("-1") << QByteArray("\xbf\xf0\x00\x00\x00\x00\x00\x00", 8) << QByteArray("\x00\x00\x00\x00\x00\x00\xf0\xbf", 8) << (int) QDataStream::Ok << (double) -1; + QTest::newRow("1") << QByteArray("\x3f\xf0\x00\x00\x00\x00\x00\x00", 8) << QByteArray("\x00\x00\x00\x00\x00\x00\xf0\x3f", 8) << (int) QDataStream::Ok << (double) 1; + QTest::newRow("37") << QByteArray("\x40\x42\x80\x00\x00\x00\x00\x00", 8) << QByteArray("\x00\x00\x00\x00\x00\x80\x42\x40", 8) << (int) QDataStream::Ok << (double) 37; + QTest::newRow("37j") << QByteArray("\x40\x42\x80\x00\x00\x00\x00\x00j", 9) << QByteArray("\x00\x00\x00\x00\x00\x80\x42\x40j", 9) << (int) QDataStream::Ok << (double) 37; + QTest::newRow("3.14") << QByteArray("\x40\x09\x1e\xb8\x60\x00\x00\x00", 8) << QByteArray("\x00\x00\x00\x60\xb8\x1e\x09\x40", 8) << (int) QDataStream::Ok << (double) 3.14; + QTest::newRow("1234.5678") << QByteArray("\x40\x93\x4a\x45\x6d\x5c\xfa\xad", 8) << QByteArray("\xad\xfa\x5c\x6d\x45\x4a\x93\x40", 8) << (int) QDataStream::Ok << (double) 1234.5678; + + // past end + QTest::newRow("empty") << QByteArray() << QByteArray() << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 1") << QByteArray("", 1) << QByteArray("", 1) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 2") << QByteArray("\x25", 1) << QByteArray("\x25", 1) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 3") << QByteArray("11", 2) << QByteArray("11", 2) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 4") << QByteArray("111", 3) << QByteArray("111", 3) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 5") << QByteArray("1111", 4) << QByteArray("1111", 4) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 6") << QByteArray("11111", 5) << QByteArray("11111", 5) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 7") << QByteArray("111111", 6) << QByteArray("111111", 6) << (int) QDataStream::ReadPastEnd << double(0); + QTest::newRow("end 8") << QByteArray("1111111", 7) << QByteArray("1111111", 7) << (int) QDataStream::ReadPastEnd << double(0); +} + +TEST_FLOAT(double) + +void tst_QDataStream::status_charptr_QByteArray_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<QByteArray>("expectedString"); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QByteArray oneMbMinus1(1024 * 1024 - 1, '\0'); + for (int i = 0; i < oneMbMinus1.size(); ++i) + oneMbMinus1[i] = 0x1 | (8 * ((uchar)i / 9)); + QByteArray threeMbMinus1 = oneMbMinus1 + 'j' + oneMbMinus1 + 'k' + oneMbMinus1; +#endif + + // ok + QTest::newRow("size 0") << QByteArray("\x00\x00\x00\x00", 4) << (int) QDataStream::Ok << QByteArray(); + QTest::newRow("size 1") << QByteArray("\x00\x00\x00\x01j", 5) << (int) QDataStream::Ok << QByteArray("j"); + QTest::newRow("size 2") << QByteArray("\x00\x00\x00\x02jk", 6) << (int) QDataStream::Ok << QByteArray("jk"); + QTest::newRow("size 3") << QByteArray("\x00\x00\x00\x03jkl", 7) << (int) QDataStream::Ok << QByteArray("jkl"); + QTest::newRow("size 4") << QByteArray("\x00\x00\x00\x04jklm", 8) << (int) QDataStream::Ok << QByteArray("jklm"); + QTest::newRow("size 4j") << QByteArray("\x00\x00\x00\x04jklmj", 8) << (int) QDataStream::Ok << QByteArray("jklm"); +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QTest::newRow("size 1MB-1") << QByteArray("\x00\x0f\xff\xff", 4) + oneMbMinus1 + QByteArray("j") << (int) QDataStream::Ok << oneMbMinus1; + QTest::newRow("size 1MB") << QByteArray("\x00\x10\x00\x00", 4) + oneMbMinus1 + QByteArray("jkl") << (int) QDataStream::Ok << oneMbMinus1 + "j"; + QTest::newRow("size 1MB+1") << QByteArray("\x00\x10\x00\x01", 4) + oneMbMinus1 + QByteArray("jkl") << (int) QDataStream::Ok << oneMbMinus1 + "jk"; + QTest::newRow("size 3MB-1") << QByteArray("\x00\x2f\xff\xff", 4) + threeMbMinus1 + QByteArray("j") << (int) QDataStream::Ok << threeMbMinus1; + QTest::newRow("size 3MB") << QByteArray("\x00\x30\x00\x00", 4) + threeMbMinus1 + QByteArray("jkl") << (int) QDataStream::Ok << threeMbMinus1 + "j"; + QTest::newRow("size 3MB+1") << QByteArray("\x00\x30\x00\x01", 4) + threeMbMinus1 + QByteArray("jkl") << (int) QDataStream::Ok << threeMbMinus1 + "jk"; +#endif + + // past end + QTest::newRow("empty") << QByteArray() << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("trunclen 1") << QByteArray("x") << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("trunclen 2") << QByteArray("xx") << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("trunclen 3") << QByteArray("xxx") << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("truncdata 1") << QByteArray("xxxx") << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("truncdata 2") << QByteArray("xxxxyyyy") << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("badsize 1") << QByteArray("\x00\x00\x00\x01", 4) << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("badsize 2") << QByteArray("\x00\x00\x00\x02j", 5) << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("badsize 3") << QByteArray("\x00\x00\x00\x03jk", 6) << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("badsize 4") << QByteArray("\x00\x00\x00\x04jkl", 7) << (int) QDataStream::ReadPastEnd << QByteArray(); +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QTest::newRow("badsize 1MB") << QByteArray("\x00\x10\x00\x00", 4) + oneMbMinus1 << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("badsize 1MB+1") << QByteArray("\x00\x10\x00\x01", 4) + oneMbMinus1 + QByteArray("j") << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("badsize 3MB") << QByteArray("\x00\x30\x00\x00", 4) + threeMbMinus1 << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("badsize 3MB+1") << QByteArray("\x00\x30\x00\x01", 4) + threeMbMinus1 + QByteArray("j") << (int) QDataStream::ReadPastEnd << QByteArray(); +#endif + QTest::newRow("size -1") << QByteArray("\xff\xff\xff\xff", 4) << (int) QDataStream::ReadPastEnd << QByteArray(); + QTest::newRow("size -2") << QByteArray("\xff\xff\xff\xfe", 4) << (int) QDataStream::ReadPastEnd << QByteArray(); +} + +void tst_QDataStream::status_charptr_QByteArray() +{ + QFETCH(QByteArray, data); + QFETCH(int, expectedStatus); + QFETCH(QByteArray, expectedString); + + { + QDataStream stream(&data, QIODevice::ReadOnly); + char *buf; + stream >> buf; + + QCOMPARE((int)qstrlen(buf), expectedString.size()); + QCOMPARE(QByteArray(buf), expectedString); + QCOMPARE(int(stream.status()), expectedStatus); + delete [] buf; + } + { + QDataStream stream(&data, QIODevice::ReadOnly); + char *buf; + uint len; + stream.readBytes(buf, len); + + QCOMPARE((int)len, expectedString.size()); + QCOMPARE(QByteArray(buf, len), expectedString); + QCOMPARE(int(stream.status()), expectedStatus); + delete [] buf; + } + { + QDataStream stream(&data, QIODevice::ReadOnly); + QByteArray buf; + stream >> buf; + + if (data.startsWith("\xff\xff\xff\xff")) { + // QByteArray, unlike 'char *', supports the null/empty distinction + QVERIFY(buf.isNull()); + } else { + QCOMPARE(buf.size(), expectedString.size()); + QCOMPARE(buf, expectedString); + QCOMPARE(int(stream.status()), expectedStatus); + } + } +} + +static QByteArray qstring2qbytearray(const QString &str) +{ + QByteArray ba(str.size() * 2 , '\0'); + for (int i = 0; i < str.size(); ++i) { + // BigEndian + ba[2 * i] = str[i].row(); + ba[2 * i + 1] = str[i].cell(); + } + return ba; +} + +void tst_QDataStream::status_QString_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<QString>("expectedString"); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QString oneMbMinus1; + oneMbMinus1.resize(1024 * 1024 - 1); + for (int i = 0; i < oneMbMinus1.size(); ++i) + oneMbMinus1[i] = 0x1 | (8 * ((uchar)i / 9)); + QString threeMbMinus1 = oneMbMinus1 + QChar('j') + oneMbMinus1 + QChar('k') + oneMbMinus1; + + QByteArray threeMbMinus1Data = qstring2qbytearray(threeMbMinus1); + QByteArray oneMbMinus1Data = qstring2qbytearray(oneMbMinus1); +#endif + + // ok + QTest::newRow("size 0") << QByteArray("\x00\x00\x00\x00", 4) << (int) QDataStream::Ok << QString(); + QTest::newRow("size 1") << QByteArray("\x00\x00\x00\x02\x00j", 6) << (int) QDataStream::Ok << QString("j"); + QTest::newRow("size 2") << QByteArray("\x00\x00\x00\x04\x00j\x00k", 8) << (int) QDataStream::Ok << QString("jk"); + QTest::newRow("size 3") << QByteArray("\x00\x00\x00\x06\x00j\x00k\x00l", 10) << (int) QDataStream::Ok << QString("jkl"); + QTest::newRow("size 4") << QByteArray("\x00\x00\x00\x08\x00j\x00k\x00l\x00m", 12) << (int) QDataStream::Ok << QString("jklm"); + QTest::newRow("size 4j") << QByteArray("\x00\x00\x00\x08\x00j\x00k\x00l\x00mjj", 14) << (int) QDataStream::Ok << QString("jklm"); +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QTest::newRow("size 1MB-1") << QByteArray("\x00\x1f\xff\xfe", 4) + oneMbMinus1Data + QByteArray("jj") << (int) QDataStream::Ok << oneMbMinus1; + QTest::newRow("size 1MB") << QByteArray("\x00\x20\x00\x00", 4) + oneMbMinus1Data + QByteArray("\x00j\x00k\x00l", 6) << (int) QDataStream::Ok << oneMbMinus1 + "j"; + QTest::newRow("size 1MB+1") << QByteArray("\x00\x20\x00\x02", 4) + oneMbMinus1Data + QByteArray("\x00j\x00k\x00l", 6) << (int) QDataStream::Ok << oneMbMinus1 + "jk"; + QTest::newRow("size 3MB-1") << QByteArray("\x00\x5f\xff\xfe", 4) + threeMbMinus1Data + QByteArray("jj") << (int) QDataStream::Ok << threeMbMinus1; + QTest::newRow("size 3MB") << QByteArray("\x00\x60\x00\x00", 4) + threeMbMinus1Data + QByteArray("\x00j\x00k\x00l", 6) << (int) QDataStream::Ok << threeMbMinus1 + "j"; + QTest::newRow("size 3MB+1") << QByteArray("\x00\x60\x00\x02", 4) + threeMbMinus1Data + QByteArray("\x00j\x00k\x00l", 6) << (int) QDataStream::Ok << threeMbMinus1 + "jk"; +#endif + + // past end + QTest::newRow("empty") << QByteArray() << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("trunclen 1") << QByteArray("x") << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("trunclen 2") << QByteArray("xx") << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("trunclen 3") << QByteArray("xxx") << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("truncdata 1") << QByteArray("xxxx") << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("truncdata 2") << QByteArray("xxxxyyyy") << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("badsize 1") << QByteArray("\x00\x00\x00\x02", 4) << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("badsize 2") << QByteArray("\x00\x00\x00\x04jj", 6) << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("badsize 3") << QByteArray("\x00\x00\x00\x06jjkk", 8) << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("badsize 4") << QByteArray("\x00\x00\x00\x08jjkkll", 10) << (int) QDataStream::ReadPastEnd << QString(); +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QTest::newRow("badsize 1MB") << QByteArray("\x00\x20\x00\x00", 4) + oneMbMinus1Data << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("badsize 1MB+1") << QByteArray("\x00\x20\x00\x02", 4) + oneMbMinus1Data + QByteArray("j") << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("badsize 3MB") << QByteArray("\x00\x60\x00\x00", 4) + threeMbMinus1Data << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("badsize 3MB+1") << QByteArray("\x00\x60\x00\x02", 4) + threeMbMinus1Data + QByteArray("j") << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("size -2") << QByteArray("\xff\xff\xff\xfe", 4) << (int) QDataStream::ReadPastEnd << QString(); + QTest::newRow("size MAX") << QByteArray("\x7f\xff\xff\xfe", 4) << (int) QDataStream::ReadPastEnd << QString(); +#endif + + // corrupt data + QTest::newRow("corrupt1") << QByteArray("yyyy") << (int) QDataStream::ReadCorruptData << QString(); + QTest::newRow("size -3") << QByteArray("\xff\xff\xff\xfd", 4) << (int) QDataStream::ReadCorruptData << QString(); +} + +void tst_QDataStream::status_QString() +{ + QFETCH(QByteArray, data); + QFETCH(int, expectedStatus); + QFETCH(QString, expectedString); + + QDataStream stream(&data, QIODevice::ReadOnly); + QString str; + stream >> str; + + QCOMPARE(str.size(), expectedString.size()); + QCOMPARE(str, expectedString); + QCOMPARE(int(stream.status()), expectedStatus); +} + +static QBitArray bitarray(const QString &str) +{ + QBitArray array(str.size()); + for (int i = 0; i < str.size(); ++i) + array[i] = (str[i] != '0'); + return array; +} + +void tst_QDataStream::status_QBitArray_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<int>("expectedStatus"); + QTest::addColumn<QBitArray>("expectedString"); + + // ok + QTest::newRow("size 0") << QByteArray("\x00\x00\x00\x00", 4) << (int) QDataStream::Ok << QBitArray(); + QTest::newRow("size 1a") << QByteArray("\x00\x00\x00\x01\x00", 5) << (int) QDataStream::Ok << bitarray("0"); + QTest::newRow("size 1b") << QByteArray("\x00\x00\x00\x01\x01", 5) << (int) QDataStream::Ok << bitarray("1"); + QTest::newRow("size 2") << QByteArray("\x00\x00\x00\x02\x03", 5) << (int) QDataStream::Ok << bitarray("11"); + QTest::newRow("size 3") << QByteArray("\x00\x00\x00\x03\x07", 5) << (int) QDataStream::Ok << bitarray("111"); + QTest::newRow("size 4") << QByteArray("\x00\x00\x00\x04\x0f", 5) << (int) QDataStream::Ok << bitarray("1111"); + QTest::newRow("size 5") << QByteArray("\x00\x00\x00\x05\x1f", 5) << (int) QDataStream::Ok << bitarray("11111"); + QTest::newRow("size 6") << QByteArray("\x00\x00\x00\x06\x3f", 5) << (int) QDataStream::Ok << bitarray("111111"); + QTest::newRow("size 7a") << QByteArray("\x00\x00\x00\x07\x7f", 5) << (int) QDataStream::Ok << bitarray("1111111"); + QTest::newRow("size 7b") << QByteArray("\x00\x00\x00\x07\x7e", 5) << (int) QDataStream::Ok << bitarray("0111111"); + QTest::newRow("size 7c") << QByteArray("\x00\x00\x00\x07\x00", 5) << (int) QDataStream::Ok << bitarray("0000000"); + QTest::newRow("size 7d") << QByteArray("\x00\x00\x00\x07\x39", 5) << (int) QDataStream::Ok << bitarray("1001110"); + QTest::newRow("size 8") << QByteArray("\x00\x00\x00\x08\xff", 5) << (int) QDataStream::Ok << bitarray("11111111"); + QTest::newRow("size 9") << QByteArray("\x00\x00\x00\x09\xff\x01", 6) << (int) QDataStream::Ok << bitarray("111111111"); + QTest::newRow("size 15") << QByteArray("\x00\x00\x00\x0f\xff\x7f", 6) << (int) QDataStream::Ok << bitarray("111111111111111"); + QTest::newRow("size 16") << QByteArray("\x00\x00\x00\x10\xff\xff", 6) << (int) QDataStream::Ok << bitarray("1111111111111111"); + QTest::newRow("size 17") << QByteArray("\x00\x00\x00\x11\xff\xff\x01", 7) << (int) QDataStream::Ok << bitarray("11111111111111111"); + QTest::newRow("size 32") << QByteArray("\x00\x00\x00\x20\xff\xff\xff\xff", 8) << (int) QDataStream::Ok << bitarray("11111111111111111111111111111111"); + + // past end + QTest::newRow("empty") << QByteArray() << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("badsize 0a") << QByteArray("\x00", 1) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("badsize 0a") << QByteArray("\x00\x00", 2) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("badsize 0a") << QByteArray("\x00\x00\x00", 3) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("badsize 1") << QByteArray("\x00\x00\x00\x01", 4) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("badsize 2") << QByteArray("\x00\x00\x00\x02", 4) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("badsize 3") << QByteArray("\x00\x00\x00\x03", 4) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("badsize 7") << QByteArray("\x00\x00\x00\x04", 4) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("size 8") << QByteArray("\x00\x00\x00\x08", 4) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("size 9") << QByteArray("\x00\x00\x00\x09\xff", 5) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("size 15") << QByteArray("\x00\x00\x00\x0f\xff", 5) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("size 16") << QByteArray("\x00\x00\x00\x10\xff", 5) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("size 17") << QByteArray("\x00\x00\x00\x11\xff\xff", 6) << (int) QDataStream::ReadPastEnd << QBitArray(); + QTest::newRow("size 32") << QByteArray("\x00\x00\x00\x20\xff\xff\xff", 7) << (int) QDataStream::ReadPastEnd << QBitArray(); + + // corrupt data + QTest::newRow("junk 1a") << QByteArray("\x00\x00\x00\x01\x02", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 1b") << QByteArray("\x00\x00\x00\x01\x04", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 1c") << QByteArray("\x00\x00\x00\x01\x08", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 1d") << QByteArray("\x00\x00\x00\x01\x10", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 1e") << QByteArray("\x00\x00\x00\x01\x20", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 1f") << QByteArray("\x00\x00\x00\x01\x40", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 1g") << QByteArray("\x00\x00\x00\x01\x80", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 2") << QByteArray("\x00\x00\x00\x02\x04", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 3") << QByteArray("\x00\x00\x00\x03\x08", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 4") << QByteArray("\x00\x00\x00\x04\x10", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 5") << QByteArray("\x00\x00\x00\x05\x20", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 6") << QByteArray("\x00\x00\x00\x06\x40", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); + QTest::newRow("junk 7") << QByteArray("\x00\x00\x00\x07\x80", 5) << (int) QDataStream::ReadCorruptData << QBitArray(); +} + +void tst_QDataStream::status_QBitArray() +{ + QFETCH(QByteArray, data); + QFETCH(int, expectedStatus); + QFETCH(QBitArray, expectedString); + + QDataStream stream(&data, QIODevice::ReadOnly); + QBitArray str; + stream >> str; + + QCOMPARE(int(stream.status()), expectedStatus); + QCOMPARE(str.size(), expectedString.size()); + QCOMPARE(str, expectedString); +} + +#define MAP_TEST(byteArray, expectedStatus, expectedHash) \ + { \ + QByteArray ba = byteArray; \ + QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream >> hash; \ + QCOMPARE((int)stream.status(), (int)expectedStatus); \ + QCOMPARE(hash.size(), expectedHash.size()); \ + QCOMPARE(hash, expectedHash); \ + } \ + { \ + QByteArray ba = byteArray; \ + StringMap expectedMap; \ + StringHash::const_iterator it = expectedHash.constBegin(); \ + for (; it != expectedHash.constEnd(); ++it) \ + expectedMap.insert(it.key(), it.value()); \ + QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream >> map; \ + QCOMPARE((int)stream.status(), (int)expectedStatus); \ + QCOMPARE(map.size(), expectedMap.size()); \ + QCOMPARE(map, expectedMap); \ + } + +void tst_QDataStream::status_QHash_QMap() +{ + typedef QHash<QString, QString> StringHash; + typedef QMap<QString, QString> StringMap; + StringHash hash; + StringMap map; + + StringHash hash1; + hash1.insert("", ""); + + StringHash hash2; + hash2.insert("J", "K"); + hash2.insert("L", "MN"); + + // ok + MAP_TEST(QByteArray("\x00\x00\x00\x00", 4), QDataStream::Ok, StringHash()); + MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00", 12), QDataStream::Ok, hash1); + MAP_TEST(QByteArray("\x00\x00\x00\x02\x00\x00\x00\x02\x00J\x00\x00\x00\x02\x00K" + "\x00\x00\x00\x02\x00L\x00\x00\x00\x04\x00M\x00N", 30), QDataStream::Ok, hash2); + + // past end + MAP_TEST(QByteArray(), QDataStream::ReadPastEnd, StringHash()); + MAP_TEST(QByteArray("\x00", 1), QDataStream::ReadPastEnd, StringHash()); + MAP_TEST(QByteArray("\x00\x00", 2), QDataStream::ReadPastEnd, StringHash()); + MAP_TEST(QByteArray("\x00\x00\x00", 3), QDataStream::ReadPastEnd, StringHash()); + MAP_TEST(QByteArray("\x00\x00\x00\x01", 4), QDataStream::ReadPastEnd, StringHash()); + for (int i = 4; i < 12; ++i) { + MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00", i), QDataStream::ReadPastEnd, StringHash()); + } + + // corrupt data + MAP_TEST(QByteArray("\x00\x00\x00\x01\x00\x00\x00\x01", 8), QDataStream::ReadCorruptData, StringHash()); + MAP_TEST(QByteArray("\x00\x00\x00\x02\x00\x00\x00\x01\x00J\x00\x00\x00\x01\x00K" + "\x00\x00\x00\x01\x00L\x00\x00\x00\x02\x00M\x00N", 30), QDataStream::ReadCorruptData, StringHash()); +} + +#define LIST_TEST(byteArray, expectedStatus, expectedList) \ + { \ + QByteArray ba = byteArray; \ + QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream >> list; \ + QCOMPARE((int)stream.status(), (int)expectedStatus); \ + QCOMPARE(list.size(), expectedList.size()); \ + QCOMPARE(list, expectedList); \ + } \ + { \ + LinkedList expectedLinkedList; \ + for (int i = 0; i < expectedList.count(); ++i) \ + expectedLinkedList << expectedList.at(i); \ + QByteArray ba = byteArray; \ + QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream >> linkedList; \ + QCOMPARE((int)stream.status(), (int)expectedStatus); \ + QCOMPARE(linkedList.size(), expectedLinkedList.size()); \ + QCOMPARE(linkedList, expectedLinkedList); \ + } \ + { \ + Vector expectedVector; \ + for (int i = 0; i < expectedList.count(); ++i) \ + expectedVector << expectedList.at(i); \ + QByteArray ba = byteArray; \ + QDataStream stream(&ba, QIODevice::ReadOnly); \ + stream >> vector; \ + QCOMPARE((int)stream.status(), (int)expectedStatus); \ + QCOMPARE(vector.size(), expectedVector.size()); \ + QCOMPARE(vector, expectedVector); \ + } + +void tst_QDataStream::status_QLinkedList_QList_QVector() +{ + typedef QLinkedList<QString> LinkedList; + typedef QList<QString> List; + typedef QVector<QString> Vector; + LinkedList linkedList; + List list; + Vector vector; + + LIST_TEST(QByteArray(), QDataStream::ReadPastEnd, List()); + LIST_TEST(QByteArray("\x00\x00\x00\x00", 4), QDataStream::Ok, List()); +} + +void tst_QDataStream::streamToAndFromQByteArray() +{ + QByteArray data; + QDataStream in(&data, QIODevice::WriteOnly); + QDataStream out(&data, QIODevice::ReadOnly); + + quint32 x = 0xdeadbeef; + quint32 y; + in << x; + out >> y; + + QCOMPARE(y, x); +} + +void tst_QDataStream::streamRealDataTypes() +{ + // Generate QPicture from pixmap. + QPixmap pm(open_xpm); + QVERIFY(!pm.isNull()); + QPicture picture; + picture.setBoundingRect(QRect(QPoint(0, 0), pm.size())); + QPainter painter(&picture); + painter.drawPixmap(0, 0, pm); + painter.end(); + + // Generate path + QPainterPath path; + path.lineTo(10, 0); + path.cubicTo(0, 0, 10, 10, 20, 20); + path.arcTo(4, 5, 6, 7, 8, 9); + path.quadTo(1, 2, 3, 4); + + QColor color(64, 64, 64); + color.setAlphaF(0.5); + QRadialGradient radialGradient(5, 6, 7, 8, 9); + QBrush radialBrush(radialGradient); + QConicalGradient conicalGradient(5, 6, 7); + QBrush conicalBrush(conicalGradient); + + for (int i = 0; i < 2; ++i) { + QFile file; + if (i == 0) { + file.setFileName(SRCDIR "datastream.q42"); + } else { + file.setFileName("datastream.tmp"); + + // Generate data + QVERIFY(file.open(QIODevice::WriteOnly)); + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_4_2); + stream << qreal(0) << qreal(1.0) << qreal(1.1) << qreal(3.14) << qreal(-3.14) << qreal(-1); + stream << QPointF(3, 5) << QRectF(-1, -2, 3, 4) << (QPolygonF() << QPointF(0, 0) << QPointF(1, 2)); + stream << QMatrix().rotate(90).scale(2, 2); + stream << path; + stream << picture; + stream << QTextLength(QTextLength::VariableLength, 1.5); + stream << color; + stream << radialBrush << conicalBrush; + stream << QPen(QBrush(Qt::red), 1.5); + + file.close(); + } + + QPointF point; + QRectF rect; + QPolygonF polygon; + QMatrix matrix; + QPainterPath p; + QPicture pict; + QTextLength textLength; + QColor col; + QBrush rGrad; + QBrush cGrad; + QPen pen; + + QVERIFY(file.open(QIODevice::ReadOnly)); + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_4_2); + + if (i == 0) { + // the reference stream for 4.2 contains doubles, + // so we must read them out as doubles! + double a, b, c, d, e, f; + stream >> a; + QCOMPARE(a, 0.0); + stream >> b; + QCOMPARE(b, 1.0); + stream >> c; + QCOMPARE(c, 1.1); + stream >> d; + QCOMPARE(d, 3.14); + stream >> e; + QCOMPARE(e, -3.14); + stream >> f; + QCOMPARE(f, -1.0); + } else { + qreal a, b, c, d, e, f; + stream >> a; + QCOMPARE(a, qreal(0)); + stream >> b; + QCOMPARE(b, qreal(1.0)); + stream >> c; + QCOMPARE(c, qreal(1.1)); + stream >> d; + QCOMPARE(d, qreal(3.14)); + stream >> e; + QCOMPARE(e, qreal(-3.14)); + stream >> f; + QCOMPARE(f, qreal(-1)); + } + stream >> point; + QCOMPARE(point, QPointF(3, 5)); + stream >> rect; + QCOMPARE(rect, QRectF(-1, -2, 3, 4)); + stream >> polygon; + QCOMPARE((QVector<QPointF> &)polygon, (QPolygonF() << QPointF(0, 0) << QPointF(1, 2))); + stream >> matrix; + QCOMPARE(matrix, QMatrix().rotate(90).scale(2, 2)); + stream >> p; + QCOMPARE(p, path); + if (i == 1) { + stream >> pict; + + QByteArray pictA, pictB; + QBuffer bufA, bufB; + QVERIFY(bufA.open(QIODevice::ReadWrite)); + QVERIFY(bufB.open(QIODevice::ReadWrite)); + + picture.save(&bufA); + pict.save(&bufB); + + QCOMPARE(pictA, pictB); + } + stream >> textLength; + QCOMPARE(textLength, QTextLength(QTextLength::VariableLength, 1.5)); + stream >> col; + QCOMPARE(col, color); + stream >> rGrad; + QCOMPARE(rGrad.style(), radialBrush.style()); + QCOMPARE(rGrad.matrix(), radialBrush.matrix()); + QCOMPARE(rGrad.gradient()->type(), radialBrush.gradient()->type()); + QCOMPARE(rGrad.gradient()->stops(), radialBrush.gradient()->stops()); + QCOMPARE(rGrad.gradient()->spread(), radialBrush.gradient()->spread()); + QCOMPARE(((QRadialGradient *)rGrad.gradient())->center(), ((QRadialGradient *)radialBrush.gradient())->center()); + QCOMPARE(((QRadialGradient *)rGrad.gradient())->focalPoint(), ((QRadialGradient *)radialBrush.gradient())->focalPoint()); + QCOMPARE(((QRadialGradient *)rGrad.gradient())->radius(), ((QRadialGradient *)radialBrush.gradient())->radius()); + stream >> cGrad; + QCOMPARE(cGrad.style(), conicalBrush.style()); + QCOMPARE(cGrad.matrix(), conicalBrush.matrix()); + QCOMPARE(cGrad.gradient()->type(), conicalBrush.gradient()->type()); + QCOMPARE(cGrad.gradient()->stops(), conicalBrush.gradient()->stops()); + QCOMPARE(cGrad.gradient()->spread(), conicalBrush.gradient()->spread()); + QCOMPARE(((QConicalGradient *)cGrad.gradient())->center(), ((QConicalGradient *)conicalBrush.gradient())->center()); + QCOMPARE(((QConicalGradient *)cGrad.gradient())->angle(), ((QConicalGradient *)conicalBrush.gradient())->angle()); + + QCOMPARE(cGrad, conicalBrush); + stream >> pen; + QCOMPARE(pen.widthF(), qreal(1.5)); + + QCOMPARE(stream.status(), QDataStream::Ok); + } +} + +void tst_QDataStream::compatibility_Qt3() +{ + QByteArray ba("hello"); + QVariant var = ba; + const quint32 invalidColor = 0x49000000; + QByteArray stream; + { + QDataStream out(&stream, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_3_3); + out << var; + out << QColor(); + out << QColor(Qt::darkYellow); + out << QColor(Qt::darkCyan); + out << invalidColor; + } + { + QDataStream in(stream); + in.setVersion(QDataStream::Qt_3_3); + + //task 196100 + quint32 type; + in >> type; + //29 is the type of a QByteArray in Qt3 + QCOMPARE(type, quint32(29)); + QByteArray ba2; + in >> ba2; + QCOMPARE(ba2, ba); + + //task196415 + quint32 color; + in >> color; + QCOMPARE(color, invalidColor); + in >> color; + QCOMPARE(color, QColor(Qt::darkYellow).rgb()); + QColor col; + in >> col; + QCOMPARE(col, QColor(Qt::darkCyan)); + in >> col; + QVERIFY(!col.isValid()); + } + { + QLinearGradient gradient(QPointF(0,0), QPointF(1,1)); + gradient.setColorAt(0, Qt::red); + gradient.setColorAt(1, Qt::blue); + + QBrush brush(gradient); + QPalette palette; + palette.setBrush(QPalette::Button, brush); + palette.setColor(QPalette::Light, Qt::green); + + QByteArray stream; + { + QDataStream out(&stream, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_3_3); + out << palette; + out << brush; + } + QBrush in_brush; + QPalette in_palette; + { + QDataStream in(stream); + in.setVersion(QDataStream::Qt_3_3); + in >> in_palette; + in >> in_brush; + } + QVERIFY(in_brush.style() == Qt::NoBrush); + QVERIFY(in_palette.brush(QPalette::Button).style() == Qt::NoBrush); + QVERIFY(in_palette.color(QPalette::Light) == Qt::green); + } +} + +void tst_QDataStream::compatibility_Qt2() +{ + QLinearGradient gradient(QPointF(0,0), QPointF(1,1)); + gradient.setColorAt(0, Qt::red); + gradient.setColorAt(1, Qt::blue); + + QBrush brush(gradient); + QPalette palette; + palette.setBrush(QPalette::Button, brush); + palette.setColor(QPalette::Light, Qt::green); + + QByteArray stream; + { + QDataStream out(&stream, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_2_1); + out << palette; + out << brush; + } + QBrush in_brush; + QPalette in_palette; + { + QDataStream in(stream); + in.setVersion(QDataStream::Qt_2_1); + in >> in_palette; + in >> in_brush; + } + QVERIFY(in_brush.style() == Qt::NoBrush); + QVERIFY(in_palette.brush(QPalette::Button).style() == Qt::NoBrush); + QVERIFY(in_palette.color(QPalette::Light) == Qt::green); +} + +void tst_QDataStream::floatingPointPrecision() +{ + QByteArray ba; + { + QDataStream stream(&ba, QIODevice::WriteOnly); + QCOMPARE(QDataStream::DoublePrecision, stream.floatingPointPrecision()); + + float f = 123.0f; + stream << f; + QCOMPARE(ba.size(), int(sizeof(double))); + + double d = 234.0; + stream << d; + QCOMPARE(ba.size(), int(sizeof(double)*2)); + + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + + f = 123.0f; + stream << f; + QCOMPARE(ba.size(), int(sizeof(double)*2 + sizeof(float))); + + d = 234.0; + stream << d; + QCOMPARE(ba.size(), int(sizeof(double)*2 + sizeof(float)*2)); + } + + { + QDataStream stream(ba); + + float f = 0.0f; + stream >> f; + QCOMPARE(123.0f, f); + + double d = 0.0; + stream >> d; + QCOMPARE(234.0, d); + + f = 0.0f; + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + stream >> f; + QCOMPARE(123.0f, f); + + d = 0.0; + stream >> d; + QCOMPARE(234.0, d); + } + +} + +QTEST_MAIN(tst_QDataStream) +#include "tst_qdatastream.moc" + diff --git a/tests/auto/corelib/io/qdebug/.gitignore b/tests/auto/corelib/io/qdebug/.gitignore new file mode 100644 index 0000000000..af993e9625 --- /dev/null +++ b/tests/auto/corelib/io/qdebug/.gitignore @@ -0,0 +1 @@ +tst_qdebug diff --git a/tests/auto/corelib/io/qdebug/qdebug.pro b/tests/auto/corelib/io/qdebug/qdebug.pro new file mode 100644 index 0000000000..2b5716860c --- /dev/null +++ b/tests/auto/corelib/io/qdebug/qdebug.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qdebug.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp new file mode 100644 index 0000000000..772fd9fd04 --- /dev/null +++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore/QtCore> +#include <QtCore/QtDebug> +#include <QtTest/QtTest> + +class tst_QDebug: public QObject +{ + Q_OBJECT +private slots: + void assignment() const; + void warningWithoutDebug() const; + void criticalWithoutDebug() const; + void debugWithQBool() const; + void veryLongWarningMessage() const; + void qDebugQStringRef() const; +}; + +void tst_QDebug::assignment() const +{ + QDebug debug1(QtDebugMsg); + QDebug debug2(QtWarningMsg); + + QTest::ignoreMessage(QtDebugMsg, "foo "); + QTest::ignoreMessage(QtWarningMsg, "bar 1 2 "); + + debug1 << "foo"; + debug2 << "bar"; + debug1 = debug2; + debug1 << "1"; + debug2 << "2"; +} + +static QtMsgType s_msgType; +static QByteArray s_msg; + +static void myMessageHandler(QtMsgType type, const char *msg) +{ + s_msg = msg; + s_msgType = type; +} + +/*! \internal + The qWarning() stream should be usable even if QT_NO_DEBUG is defined. + */ +void tst_QDebug::warningWithoutDebug() const +{ + qInstallMsgHandler(myMessageHandler); + { qWarning() << "A qWarning() message"; } + QCOMPARE(s_msgType, QtWarningMsg); + QCOMPARE(QString::fromLatin1(s_msg.data()), QString::fromLatin1("A qWarning() message ")); + qInstallMsgHandler(0); +} + +/*! \internal + The qCritical() stream should be usable even if QT_NO_DEBUG is defined. + */ +void tst_QDebug::criticalWithoutDebug() const +{ + qInstallMsgHandler(myMessageHandler); + { qCritical() << "A qCritical() message"; } + QCOMPARE(s_msgType, QtCriticalMsg); + QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("A qCritical() message ")); + qInstallMsgHandler(0); +} + +void tst_QDebug::debugWithQBool() const +{ + qInstallMsgHandler(myMessageHandler); + { qDebug() << QBool(false) << QBool(true); } + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("false true ")); + qInstallMsgHandler(0); +} + +void tst_QDebug::veryLongWarningMessage() const +{ + qInstallMsgHandler(myMessageHandler); + QString test; + { + QString part("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); + for (int i = 0; i < 1000; ++i) + test.append(part); + qWarning("Test output:\n%s\nend", qPrintable(test)); + } + QCOMPARE(s_msgType, QtWarningMsg); + QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("Test output:\n")+test+QString::fromLatin1("\nend")); + qInstallMsgHandler(0); +} + +void tst_QDebug::qDebugQStringRef() const +{ + /* Use a basic string. */ + { + const QString in(QLatin1String("input")); + const QStringRef inRef(&in); + + qInstallMsgHandler(myMessageHandler); + { qDebug() << inRef; } + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("\"input\" ")); + qInstallMsgHandler(0); + } + + /* Use a null QStringRef. */ + { + const QStringRef inRef; + + qInstallMsgHandler(myMessageHandler); + { qDebug() << inRef; } + QCOMPARE(s_msgType, QtDebugMsg); + QCOMPARE(QString::fromLatin1(s_msg), QString::fromLatin1("\"\" ")); + qInstallMsgHandler(0); + } +} + +QTEST_MAIN(tst_QDebug); +#include "tst_qdebug.moc" diff --git a/tests/auto/corelib/io/qdir/.gitignore b/tests/auto/corelib/io/qdir/.gitignore new file mode 100644 index 0000000000..889f51029c --- /dev/null +++ b/tests/auto/corelib/io/qdir/.gitignore @@ -0,0 +1 @@ +tst_qdir diff --git a/tests/auto/corelib/io/qdir/entrylist/directory/dummy b/tests/auto/corelib/io/qdir/entrylist/directory/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/entrylist/directory/dummy diff --git a/tests/auto/corelib/io/qdir/entrylist/file b/tests/auto/corelib/io/qdir/entrylist/file new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/entrylist/file diff --git a/tests/auto/corelib/io/qdir/qdir.pro b/tests/auto/corelib/io/qdir/qdir.pro new file mode 100644 index 0000000000..fc266a2a97 --- /dev/null +++ b/tests/auto/corelib/io/qdir/qdir.pro @@ -0,0 +1,24 @@ +load(qttest_p4) +SOURCES += tst_qdir.cpp +RESOURCES += qdir.qrc +QT = core + +wince*|symbian { + DirFiles.files = testdir testData searchdir resources entrylist types tst_qdir.cpp + DirFiles.path = . + DEPLOYMENT += DirFiles +} + +wince* { + DEFINES += SRCDIR=\\\"\\\" +} else:symbian { + TARGET.CAPABILITY += AllFiles + TARGET.UID3 = 0xE0340002 + DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x","")) + LIBS += -lefsrv + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qdir/qdir.qrc b/tests/auto/corelib/io/qdir/qdir.qrc new file mode 100644 index 0000000000..4c5b5af3b8 --- /dev/null +++ b/tests/auto/corelib/io/qdir/qdir.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/tst_qdir/"> + <file>resources/entryList/</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qdir/resources/entryList/file1.data b/tests/auto/corelib/io/qdir/resources/entryList/file1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/resources/entryList/file1.data diff --git a/tests/auto/corelib/io/qdir/resources/entryList/file2.data b/tests/auto/corelib/io/qdir/resources/entryList/file2.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/resources/entryList/file2.data diff --git a/tests/auto/corelib/io/qdir/resources/entryList/file3.data b/tests/auto/corelib/io/qdir/resources/entryList/file3.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/resources/entryList/file3.data diff --git a/tests/auto/corelib/io/qdir/resources/entryList/file4.nothing b/tests/auto/corelib/io/qdir/resources/entryList/file4.nothing new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/resources/entryList/file4.nothing diff --git a/tests/auto/corelib/io/qdir/searchdir/subdir1/picker.png b/tests/auto/corelib/io/qdir/searchdir/subdir1/picker.png new file mode 100644 index 0000000000..52eee4fe28 --- /dev/null +++ b/tests/auto/corelib/io/qdir/searchdir/subdir1/picker.png @@ -0,0 +1 @@ +mostly empty diff --git a/tests/auto/corelib/io/qdir/searchdir/subdir2/picker.png b/tests/auto/corelib/io/qdir/searchdir/subdir2/picker.png new file mode 100644 index 0000000000..52eee4fe28 --- /dev/null +++ b/tests/auto/corelib/io/qdir/searchdir/subdir2/picker.png @@ -0,0 +1 @@ +mostly empty diff --git a/tests/auto/corelib/io/qdir/testData/empty b/tests/auto/corelib/io/qdir/testData/empty new file mode 100644 index 0000000000..a437d5b711 --- /dev/null +++ b/tests/auto/corelib/io/qdir/testData/empty @@ -0,0 +1 @@ +this is just so QDir has something to dive into. diff --git a/tests/auto/corelib/io/qdir/testdir/dir/qdir.pro b/tests/auto/corelib/io/qdir/testdir/dir/qdir.pro new file mode 100644 index 0000000000..139597f9cb --- /dev/null +++ b/tests/auto/corelib/io/qdir/testdir/dir/qdir.pro @@ -0,0 +1,2 @@ + + diff --git a/tests/auto/corelib/io/qdir/testdir/dir/qrc_qdir.cpp b/tests/auto/corelib/io/qdir/testdir/dir/qrc_qdir.cpp new file mode 100644 index 0000000000..74114760c9 --- /dev/null +++ b/tests/auto/corelib/io/qdir/testdir/dir/qrc_qdir.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + diff --git a/tests/auto/corelib/io/qdir/testdir/dir/tmp/empty b/tests/auto/corelib/io/qdir/testdir/dir/tmp/empty new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/testdir/dir/tmp/empty diff --git a/tests/auto/corelib/io/qdir/testdir/dir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/testdir/dir/tst_qdir.cpp new file mode 100644 index 0000000000..74114760c9 --- /dev/null +++ b/tests/auto/corelib/io/qdir/testdir/dir/tst_qdir.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + diff --git a/tests/auto/corelib/io/qdir/testdir/spaces/foo. bar b/tests/auto/corelib/io/qdir/testdir/spaces/foo. bar new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/testdir/spaces/foo. bar diff --git a/tests/auto/corelib/io/qdir/testdir/spaces/foo.bar b/tests/auto/corelib/io/qdir/testdir/spaces/foo.bar new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/testdir/spaces/foo.bar diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp new file mode 100644 index 0000000000..700e11a347 --- /dev/null +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -0,0 +1,1952 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qdir.h> +#include <qfileinfo.h> +#include <qregexp.h> +#include <qstringlist.h> +#include "../../../network-settings.h" + +#if defined(Q_OS_WIN) +#define _WIN32_WINNT 0x500 +#endif + +#include "../../../../shared/filesystem.h" + +#if defined(Q_OS_SYMBIAN) +# include <f32file.h> +# define STRINGIFY(x) #x +# define TOSTRING(x) STRINGIFY(x) +# define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) "/" +#elif defined(Q_OS_UNIX) +# include <unistd.h> +# include <sys/stat.h> +#endif + +#if defined(Q_OS_VXWORKS) +#define Q_NO_SYMLINKS +#endif + +#if defined(Q_OS_SYMBIAN) +#define Q_NO_SYMLINKS +#define Q_NO_SYMLINKS_TO_DIRS +#endif + + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QDir : public QObject +{ +Q_OBJECT + +public: + tst_QDir(); + virtual ~tst_QDir(); + +private slots: + void getSetCheck(); + void construction(); + + void setPath_data(); + void setPath(); + + void entryList_data(); + void entryList(); + + void entryListSimple_data(); + void entryListSimple(); + + void entryListWithSymLinks(); + + void mkdir_data(); + void mkdir(); + + void makedirReturnCode(); + + void rmdir_data(); + void rmdir(); + + void exists_data(); + void exists(); + + void isRelativePath_data(); + void isRelativePath(); + + void canonicalPath_data(); + void canonicalPath(); + + void current_data(); + void current(); + + void cd_data(); + void cd(); + + void setNameFilters_data(); + void setNameFilters(); + + void cleanPath_data(); + void cleanPath(); + + void compare(); + void QDir_default(); + + void filePath_data(); + void filePath(); + + void absoluteFilePath_data(); + void absoluteFilePath(); + + void absolutePath_data(); + void absolutePath(); + + void relativeFilePath_data(); + void relativeFilePath(); + + void remove(); + void rename(); + + void exists2_data(); + void exists2(); + + void dirName_data(); + void dirName(); + + void operator_eq(); + + void dotAndDotDot(); + void homePath(); + void tempPath(); + void rootPath(); + + void nativeSeparators(); + + void searchPaths(); + void searchPaths_data(); + + void entryListWithSearchPaths(); + + void longFileName_data(); + void longFileName(); + + void updateFileLists(); + + void detachingOperations(); + + void testCaching(); + + void isRoot_data(); + void isRoot(); + +#ifndef QT_NO_REGEXP + void match_data(); + void match(); +#endif + + void drives(); + + void arrayOperator(); + + void equalityOperator_data(); + void equalityOperator(); + + void isRelative_data(); + void isRelative(); + + void isReadable(); +}; + +// Testing get/set functions +void tst_QDir::getSetCheck() +{ + QDir obj1; + // Filters QDir::filter() + // void QDir::setFilter(Filters) + obj1.setFilter(QDir::Filters(QDir::Dirs)); + QCOMPARE(QDir::Filters(QDir::Dirs), obj1.filter()); + obj1.setFilter(QDir::Filters(QDir::Dirs | QDir::Files)); + QCOMPARE(QDir::Filters(QDir::Dirs | QDir::Files), obj1.filter()); + obj1.setFilter(QDir::Filters(QDir::NoFilter)); + QCOMPARE(QDir::Filters(QDir::NoFilter), obj1.filter()); + + // SortFlags QDir::sorting() + // void QDir::setSorting(SortFlags) + obj1.setSorting(QDir::SortFlags(QDir::Name)); + QCOMPARE(QDir::SortFlags(QDir::Name), obj1.sorting()); + obj1.setSorting(QDir::SortFlags(QDir::Name | QDir::IgnoreCase)); + QCOMPARE(QDir::SortFlags(QDir::Name | QDir::IgnoreCase), obj1.sorting()); + obj1.setSorting(QDir::SortFlags(QDir::NoSort)); + QCOMPARE(QDir::SortFlags(QDir::NoSort), obj1.sorting()); +} + +tst_QDir::tst_QDir() +{ +#ifdef Q_OS_SYMBIAN + // Can't deploy empty test dir, so create it here + QDir dir(SRCDIR); + dir.mkdir("testData"); +#endif +} + +tst_QDir::~tst_QDir() +{ +#ifdef Q_OS_SYMBIAN + // Remove created test dir + QDir dir(SRCDIR); + dir.rmdir("testData"); +#endif +} + +void tst_QDir::construction() +{ + QFileInfo myFileInfo("/machine/share/dir1/file1"); + QDir myDir(myFileInfo.absoluteDir()); // this asserted + QCOMPARE(myFileInfo.absoluteDir().absolutePath(), myDir.absolutePath()); +} + +void tst_QDir::setPath_data() +{ + QTest::addColumn<QString>("dir1"); + QTest::addColumn<QString>("dir2"); + + QTest::newRow("data0") << QString(".") << QString(".."); +#if (defined(Q_WS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("data1") << QString("c:/") << QDir::currentPath(); +#endif +} + +void tst_QDir::setPath() +{ + QFETCH(QString, dir1); + QFETCH(QString, dir2); + + QDir shared; + QDir qDir1(dir1); + QStringList entries1 = qDir1.entryList(); + shared.setPath(dir1); + QCOMPARE(shared.entryList(), entries1); + + QDir qDir2(dir2); + QStringList entries2 = qDir2.entryList(); + shared.setPath(dir2); + QCOMPARE(shared.entryList(), entries2); +} + +void tst_QDir::mkdir_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("recurse"); + + QStringList dirs; + dirs << QDir::currentPath() + "/testdir/one/two/three" + << QDir::currentPath() + "/testdir/two" + << QDir::currentPath() + "/testdir/two/three"; + QTest::newRow("data0") << dirs.at(0) << true; + QTest::newRow("data1") << dirs.at(1) << false; + QTest::newRow("data2") << dirs.at(2) << false; + + // Ensure that none of these directories already exist + QDir dir; + for (int i = 0; i < dirs.count(); ++i) + dir.rmpath(dirs.at(i)); +} + +void tst_QDir::mkdir() +{ + QFETCH(QString, path); + QFETCH(bool, recurse); + + QDir dir; + dir.rmdir(path); + if (recurse) + QVERIFY(dir.mkpath(path)); + else + QVERIFY(dir.mkdir(path)); + + //make sure it really exists (ie that mkdir returns the right value) + QFileInfo fi(path); + QVERIFY(fi.exists() && fi.isDir()); +} + +void tst_QDir::makedirReturnCode() +{ + QString dirName = QString::fromLatin1("makedirReturnCode"); + QDir::current().rmdir(dirName); // cleanup a previous run. + QDir dir(dirName); + QVERIFY(!dir.exists()); + QVERIFY(QDir::current().mkdir(dirName)); + QVERIFY(!QDir::current().mkdir(dirName)); // calling mkdir on an existing dir will fail. + QVERIFY(QDir::current().mkpath(dirName)); // calling mkpath on an existing dir will pass +} + +void tst_QDir::rmdir_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("recurse"); + + QTest::newRow("data0") << QDir::currentPath() + "/testdir/one/two/three" << true; + QTest::newRow("data1") << QDir::currentPath() + "/testdir/two/three" << false; + QTest::newRow("data2") << QDir::currentPath() + "/testdir/two" << false; +} + +void tst_QDir::rmdir() +{ + QFETCH(QString, path); + QFETCH(bool, recurse); + + QDir dir; + if (recurse) + QVERIFY(dir.rmpath(path)); + else + QVERIFY(dir.rmdir(path)); + + //make sure it really doesn't exist (ie that rmdir returns the right value) + QFileInfo fi(path); + QVERIFY(!fi.exists()); +} + +void tst_QDir::exists_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("data0") << QDir::currentPath() << true; + QTest::newRow("data0.1") << QDir::currentPath() + "/" << true; + QTest::newRow("data1") << QString("/I/Do_not_expect_this_path_to_exist/") << false; + QTest::newRow("resource0") << QString(":/tst_qdir/") << true; + QTest::newRow("resource1") << QString(":/I/Do_not_expect_this_resource_to_exist/") << false; + + QTest::newRow("simple dir") << SRCDIR "resources" << true; + QTest::newRow("simple dir with slash") << SRCDIR "resources/" << true; +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) + QTest::newRow("unc 1") << "//" + QtNetworkSettings::winServerName() << true; + QTest::newRow("unc 2") << "//" + QtNetworkSettings::winServerName() + "/" << true; + QTest::newRow("unc 3") << "//" + QtNetworkSettings::winServerName() + "/testshare" << true; + QTest::newRow("unc 4") << "//" + QtNetworkSettings::winServerName() + "/testshare/" << true; + QTest::newRow("unc 5") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp" << true; + QTest::newRow("unc 6") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp/" << true; + QTest::newRow("unc 7") << "//" + QtNetworkSettings::winServerName() + "/testshare/adirthatshouldnotexist" << false; + QTest::newRow("unc 8") << "//" + QtNetworkSettings::winServerName() + "/asharethatshouldnotexist" << false; + QTest::newRow("unc 9") << "//ahostthatshouldnotexist" << false; +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("This drive should exist") << "C:/" << true; + // find a non-existing drive and check if it does not exist + QFileInfoList drives = QFSFileEngine::drives(); + QStringList driveLetters; + for (int i = 0; i < drives.count(); ++i) { + driveLetters+=drives.at(i).absoluteFilePath(); + } + char drive = 'Z'; + QString driv; + do { + driv = QString::fromAscii("%1:/").arg(drive); + if (!driveLetters.contains(driv)) break; + --drive; + } while (drive >= 'A'); + if (drive >= 'A') { + QTest::newRow("This drive should not exist") << driv << false; + } +#endif +} + +void tst_QDir::exists() +{ + QFETCH(QString, path); + QFETCH(bool, expected); + + QDir dir(path); + QCOMPARE(dir.exists(), expected); +} + +void tst_QDir::isRelativePath_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("relative"); + + QTest::newRow("data0") << "../somedir" << true; +#if (defined(Q_WS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("data1") << "C:/sOmedir" << false; +#endif + QTest::newRow("data2") << "somedir" << true; + QTest::newRow("data3") << "/somedir" << false; + + QTest::newRow("resource0") << ":/prefix" << false; + QTest::newRow("resource1") << ":/prefix/foo.bar" << false; +} + +void tst_QDir::isRelativePath() +{ + QFETCH(QString, path); + QFETCH(bool, relative); + + QCOMPARE(QDir::isRelativePath(path),relative); +} + + +void tst_QDir::QDir_default() +{ + //default constructor QDir(); + QDir dir; // according to documentation should be currentDirPath + QCOMPARE(dir.absolutePath(), QDir::currentPath()); +} + +void tst_QDir::compare() +{ + // operator== + QDir dir; + dir.makeAbsolute(); + QVERIFY(dir == QDir::currentPath()); +} + +static QStringList filterLinks(const QStringList &list) +{ +#ifndef Q_NO_SYMLINKS + return list; +#else + QStringList result; + foreach (QString str, list) { + if (!str.endsWith(QLatin1String(".lnk"))) + result.append(str); + } + return result; +#endif +} + +void tst_QDir::entryList_data() +{ + QTest::addColumn<QString>("dirName"); // relative from current path or abs + QTest::addColumn<QStringList>("nameFilters"); + QTest::addColumn<int>("filterspec"); + QTest::addColumn<int>("sortspec"); + QTest::addColumn<QStringList>("expected"); + QTest::newRow("spaces1") << SRCDIR "testdir/spaces" << QStringList("*. bar") + << (int)(QDir::NoFilter) << (int)(QDir::NoSort) + << QStringList("foo. bar"); // notice how spaces5 works + QTest::newRow("spaces2") << SRCDIR "testdir/spaces" << QStringList("*.bar") + << (int)(QDir::NoFilter) << (int)(QDir::NoSort) + << QStringList("foo.bar"); + QTest::newRow("spaces3") << SRCDIR "testdir/spaces" << QStringList("foo.*") + << (int)(QDir::NoFilter) << (int)(QDir::NoSort) + << QString("foo. bar,foo.bar").split(','); + QTest::newRow("files1") << SRCDIR "testdir/dir" << QString("*r.cpp *.pro").split(" ") + << (int)(QDir::NoFilter) << (int)(QDir::NoSort) + << QString("qdir.pro,qrc_qdir.cpp,tst_qdir.cpp").split(','); + QTest::newRow("testdir1") << SRCDIR "testdir" << QStringList() + << (int)(QDir::AllDirs) << (int)(QDir::NoSort) + << QString(".,..,dir,spaces").split(','); +// #### this test uses filenames that cannot be represented on all filesystems we test, in +// particular HFS+ on the Mac. When checking out the files with perforce it silently ignores the +// error that it cannot represent the file names stored in the repository and the test fails. That +// is why the test is marked as 'skip' for the mac. When checking out the files with git on the mac +// the error of not being able to represent the files stored in the repository is not silently +// ignored but git reports an error. The test only tried to prevent QDir from _hanging_ when listing +// the directory. +// QTest::newRow("unprintablenames") << SRCDIR "unprintablenames" << QStringList("*") +// << (int)(QDir::NoFilter) << (int)(QDir::NoSort) +// << QString(".,..").split(","); + QTest::newRow("resources1") << QString(":/tst_qdir/resources/entryList") << QStringList("*.data") + << (int)(QDir::NoFilter) << (int)(QDir::NoSort) + << QString("file1.data,file2.data,file3.data").split(','); + QTest::newRow("resources2") << QString(":/tst_qdir/resources/entryList") << QStringList("*.data") + << (int)(QDir::Files) << (int)(QDir::NoSort) + << QString("file1.data,file2.data,file3.data").split(','); + + QTest::newRow("nofilter") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::NoFilter) << int(QDir::Name) + << filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::AllEntries") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllEntries) << int(QDir::Name) + << filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::Files") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Files) << int(QDir::Name) + << filterLinks(QString("file,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::Dirs") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Dirs) << int(QDir::Name) + << filterLinks(QString(".,..,directory,linktodirectory.lnk").split(',')); + QTest::newRow("QDir::Dirs | QDir::NoDotAndDotDot") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Dirs | QDir::NoDotAndDotDot) << int(QDir::Name) + << filterLinks(QString("directory,linktodirectory.lnk").split(',')); + QTest::newRow("QDir::AllDirs") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllDirs) << int(QDir::Name) + << filterLinks(QString(".,..,directory,linktodirectory.lnk").split(',')); + QTest::newRow("QDir::AllDirs | QDir::Dirs") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllDirs | QDir::Dirs) << int(QDir::Name) + << filterLinks(QString(".,..,directory,linktodirectory.lnk").split(',')); + QTest::newRow("QDir::AllDirs | QDir::Files") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllDirs | QDir::Files) << int(QDir::Name) + << filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::AllEntries | QDir::NoSymLinks") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllEntries | QDir::NoSymLinks) << int(QDir::Name) + << filterLinks(QString(".,..,directory,file,writable").split(',')); + QTest::newRow("QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot) << int(QDir::Name) + << filterLinks(QString("directory,file,writable").split(',')); + QTest::newRow("QDir::Files | QDir::NoSymLinks") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Files | QDir::NoSymLinks) << int(QDir::Name) + << filterLinks(QString("file,writable").split(',')); + QTest::newRow("QDir::Dirs | QDir::NoSymLinks") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Dirs | QDir::NoSymLinks) << int(QDir::Name) + << filterLinks(QString(".,..,directory").split(',')); + QTest::newRow("QDir::Drives | QDir::Files | QDir::NoDotAndDotDot") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Drives | QDir::Files | QDir::NoDotAndDotDot) << int(QDir::Name) + << filterLinks(QString("file,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::System") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::System) << int(QDir::Name) + << filterLinks(QStringList("brokenlink.lnk")); + QTest::newRow("QDir::Hidden") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Hidden) << int(QDir::Name) + << QStringList(); + QTest::newRow("QDir::System | QDir::Hidden") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::System | QDir::Hidden) << int(QDir::Name) + << filterLinks(QStringList("brokenlink.lnk")); + QTest::newRow("QDir::AllDirs | QDir::NoSymLinks") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllDirs | QDir::NoSymLinks) << int(QDir::Name) + << filterLinks(QString(".,..,directory").split(',')); + QTest::newRow("QDir::AllEntries | QDir::Hidden | QDir::System") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllEntries | QDir::Hidden | QDir::System) << int(QDir::Name) + << filterLinks(QString(".,..,brokenlink.lnk,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::AllEntries | QDir::Readable") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllEntries | QDir::Readable) << int(QDir::Name) + << filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::AllEntries | QDir::Writable") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::AllEntries | QDir::Writable) << int(QDir::Name) + << filterLinks(QString(".,..,directory,linktodirectory.lnk,writable").split(',')); + QTest::newRow("QDir::Files | QDir::Readable") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Files | QDir::Readable) << int(QDir::Name) + << filterLinks(QString("file,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::Dirs | QDir::Readable") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Dirs | QDir::Readable) << int(QDir::Name) + << filterLinks(QString(".,..,directory,linktodirectory.lnk").split(',')); + QTest::newRow("Namefilters b*") << SRCDIR "entrylist/" << QStringList("d*") + << int(QDir::NoFilter) << int(QDir::Name) + << filterLinks(QString("directory").split(',')); + QTest::newRow("Namefilters f*") << SRCDIR "entrylist/" << QStringList("f*") + << int(QDir::NoFilter) << int(QDir::Name) + << filterLinks(QString("file").split(',')); + QTest::newRow("Namefilters link*") << SRCDIR "entrylist/" << QStringList("link*") + << int(QDir::NoFilter) << int(QDir::Name) + << filterLinks(QString("linktodirectory.lnk,linktofile.lnk").split(',')); + QTest::newRow("Namefilters *to*") << SRCDIR "entrylist/" << QStringList("*to*") + << int(QDir::NoFilter) << int(QDir::Name) + << filterLinks(QString("directory,linktodirectory.lnk,linktofile.lnk").split(',')); + QTest::newRow("Sorting QDir::Name") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::NoFilter) << int(QDir::Name) + << filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(',')); + QTest::newRow("Sorting QDir::Name | QDir::Reversed") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::NoFilter) << int(QDir::Name | QDir::Reversed) + << filterLinks(QString("writable,linktofile.lnk,linktodirectory.lnk,file,directory,..,.").split(',')); + + QTest::newRow("Sorting QDir::Type") << SRCDIR "types/" << QStringList("*") + << int(QDir::NoFilter) << int(QDir::Type) + << QString(".,..,a,b,c,d,e,f,a.a,b.a,c.a,d.a,e.a,f.a,a.b,b.b,c.b,d.b,e.b,f.b,a.c,b.c,c.c,d.c,e.c,f.c").split(','); + QTest::newRow("Sorting QDir::Type | QDir::Reversed") << SRCDIR "types/" << QStringList("*") + << int(QDir::NoFilter) << int(QDir::Type | QDir::Reversed) + << QString("f.c,e.c,d.c,c.c,b.c,a.c,f.b,e.b,d.b,c.b,b.b,a.b,f.a,e.a,d.a,c.a,b.a,a.a,f,e,d,c,b,a,..,.").split(','); + QTest::newRow("Sorting QDir::Type | QDir::DirsLast") << SRCDIR "types/" << QStringList("*") + << int(QDir::NoFilter) << int(QDir::Type | QDir::DirsLast) + << QString("a,b,c,a.a,b.a,c.a,a.b,b.b,c.b,a.c,b.c,c.c,.,..,d,e,f,d.a,e.a,f.a,d.b,e.b,f.b,d.c,e.c,f.c").split(','); + QTest::newRow("Sorting QDir::Type | QDir::DirsFirst") << SRCDIR "types/" << QStringList("*") + << int(QDir::NoFilter) << int(QDir::Type | QDir::DirsFirst) + << QString(".,..,d,e,f,d.a,e.a,f.a,d.b,e.b,f.b,d.c,e.c,f.c,a,b,c,a.a,b.a,c.a,a.b,b.b,c.b,a.c,b.c,c.c").split(','); + QTest::newRow("Sorting QDir::Size") << SRCDIR "types/" << QStringList("*") + << int(QDir::AllEntries|QDir::NoDotAndDotDot) << int(QDir::Size | QDir::DirsFirst) + << QString("d,d.a,d.b,d.c,e,e.a,e.b,e.c,f,f.a,f.b,f.c,c.a,c.b,c.c,b.a,b.c,b.b,a.c,a.b,a.a,a,b,c").split(','); + QTest::newRow("Sorting QDir::Size | QDir::Reversed") << SRCDIR "types/" << QStringList("*") + << int(QDir::AllEntries|QDir::NoDotAndDotDot) << int(QDir::Size | QDir::Reversed | QDir::DirsLast) + << QString("c,b,a,a.a,a.b,a.c,b.b,b.c,b.a,c.c,c.b,c.a,f.c,f.b,f.a,f,e.c,e.b,e.a,e,d.c,d.b,d.a,d").split(','); +} + +void tst_QDir::entryList() +{ + QFETCH(QString, dirName); + QFETCH(QStringList, nameFilters); + QFETCH(int, filterspec); + QFETCH(int, sortspec); + QFETCH(QStringList, expected); + + QFile(SRCDIR "entrylist/writable").open(QIODevice::ReadWrite); + QFile(SRCDIR "entrylist/file").setPermissions(QFile::ReadOwner | QFile::ReadUser); + QFile::remove(SRCDIR "entrylist/linktofile"); + QFile::remove(SRCDIR "entrylist/linktodirectory"); + QFile::remove(SRCDIR "entrylist/linktofile.lnk"); + QFile::remove(SRCDIR "entrylist/linktodirectory.lnk"); + QFile::remove(SRCDIR "entrylist/brokenlink.lnk"); + QFile::remove(SRCDIR "entrylist/brokenlink"); + + // WinCE/Symbian does not have . and .. in the directory listing +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + expected.removeAll("."); + expected.removeAll(".."); +#endif + +#ifndef Q_NO_SYMLINKS +#if defined(Q_OS_WIN) + // ### Sadly, this is a platform difference right now. + QFile::link(SRCDIR "entryList/file", SRCDIR "entrylist/linktofile.lnk"); + QFile::link(SRCDIR "entryList/directory", SRCDIR "entrylist/linktodirectory.lnk"); + QFile::link(SRCDIR "entryList/nothing", SRCDIR "entrylist/brokenlink.lnk"); +#elif defined(Q_OS_SYMBIAN) + // Symbian doesn't support links to directories + expected.removeAll("linktodirectory.lnk"); + + // Expecting failures from a couple of OpenC bugs. Do checks only once. + static int xFailChecked = false; + static int expectedFail1 = false; + static int expectedFail2 = false; + + if (!expectedFail1) { + // Can't create link if file doesn't exist in symbian, so create file temporarily, + // But only if testing for + QFile tempFile(SRCDIR "entryList/nothing"); + tempFile.open(QIODevice::WriteOnly); + tempFile.link(SRCDIR "entryList/brokenlink.lnk"); + tempFile.remove(); + } + + if (!expectedFail2) { + QFile::link(SRCDIR "entryList/file", SRCDIR "entrylist/linktofile.lnk"); + } + + if (!xFailChecked) { + // ### Until OpenC supports stat correctly for symbolic links, expect them to fail. + expectedFail1 = QFileInfo(SRCDIR "entryList/brokenlink.lnk").exists(); + expectedFail2 = !(QFileInfo(SRCDIR "entryList/linktofile.lnk").isFile()); + + QEXPECT_FAIL("", "OpenC bug, stat for broken links returns normally, when it should return error.", Continue); + QVERIFY(!expectedFail1); + + QEXPECT_FAIL("", "OpenC bug, stat for file links doesn't indicate them as such.", Continue); + QVERIFY(!expectedFail2); + xFailChecked = true; + } + + if (expectedFail1) { + expected.removeAll("brokenlink.lnk"); + QFile::remove(SRCDIR "entrylist/brokenlink.lnk"); + } + + if (expectedFail2) { + expected.removeAll("linktofile.lnk"); + QFile::remove(SRCDIR "entrylist/linktofile.lnk"); + } +#else + QFile::link("file", SRCDIR "entrylist/linktofile.lnk"); + QFile::link("directory", SRCDIR "entrylist/linktodirectory.lnk"); + QFile::link("nothing", SRCDIR "entrylist/brokenlink.lnk"); +#endif +#endif //Q_NO_SYMLINKS + +#ifdef Q_WS_MAC + if (qstrcmp(QTest::currentDataTag(), "unprintablenames") == 0) + QSKIP("p4 doesn't sync the files with the unprintable names properly on Mac",SkipSingle); +#endif + QDir dir(dirName); + QVERIFY(dir.exists()); + + QStringList actual = dir.entryList(nameFilters, (QDir::Filters)filterspec, + (QDir::SortFlags)sortspec); + + int max = qMin(actual.count(), expected.count()); + + if (qstrcmp(QTest::currentDataTag(), "unprintablenames") == 0) { + // The purpose of this entry is to check that QDir doesn't + // lock up. The actual result depends on the file system. + return; + } + bool doContentCheck = true; +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + if (qstrcmp(QTest::currentDataTag(), "QDir::AllEntries | QDir::Writable") == 0) { + // for root, everything is writeable + if (::getuid() == 0) + doContentCheck = false; + } +#endif + + if (doContentCheck) { + for (int i=0; i<max; ++i) + QCOMPARE(actual[i], expected[i]); + + QCOMPARE(actual.count(), expected.count()); + } + +#if defined(Q_OS_SYMBIAN) + // Test cleanup on device requires setting the permissions back to normal + QFile(SRCDIR "entrylist/file").setPermissions(QFile::WriteUser | QFile::ReadUser); +#endif + + QFile::remove(SRCDIR "entrylist/writable"); + QFile::remove(SRCDIR "entrylist/linktofile"); + QFile::remove(SRCDIR "entrylist/linktodirectory"); + QFile::remove(SRCDIR "entrylist/linktofile.lnk"); + QFile::remove(SRCDIR "entrylist/linktodirectory.lnk"); + QFile::remove(SRCDIR "entrylist/brokenlink.lnk"); + QFile::remove(SRCDIR "entrylist/brokenlink"); +} + +void tst_QDir::entryListSimple_data() +{ + QTest::addColumn<QString>("dirName"); + QTest::addColumn<int>("countMin"); + + QTest::newRow("data2") << "do_not_expect_this_path_to_exist/" << 0; +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QTest::newRow("simple dir") << SRCDIR "resources" << 0; + QTest::newRow("simple dir with slash") << SRCDIR "resources/" << 0; +#else + QTest::newRow("simple dir") << SRCDIR "resources" << 2; + QTest::newRow("simple dir with slash") << SRCDIR "resources/" << 2; +#endif + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QTest::newRow("unc 1") << "//" + QtNetworkSettings::winServerName() << 2; + QTest::newRow("unc 2") << "//" + QtNetworkSettings::winServerName() + "/" << 2; + QTest::newRow("unc 3") << "//" + QtNetworkSettings::winServerName() + "/testshare" << 2; + QTest::newRow("unc 4") << "//" + QtNetworkSettings::winServerName() + "/testshare/" << 2; + QTest::newRow("unc 5") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp" << 2; + QTest::newRow("unc 6") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp/" << 2; + QTest::newRow("unc 7") << "//" + QtNetworkSettings::winServerName() + "/testshare/adirthatshouldnotexist" << 0; + QTest::newRow("unc 8") << "//" + QtNetworkSettings::winServerName() + "/asharethatshouldnotexist" << 0; + QTest::newRow("unc 9") << "//ahostthatshouldnotexist" << 0; +#endif +} + +void tst_QDir::entryListSimple() +{ + QFETCH(QString, dirName); + QFETCH(int, countMin); + + QDir dir(dirName); + QStringList actual = dir.entryList(); + QVERIFY(actual.count() >= countMin); +} + +void tst_QDir::entryListWithSymLinks() +{ +#ifndef Q_NO_SYMLINKS +# ifndef Q_NO_SYMLINKS_TO_DIRS + QFile::remove("myLinkToDir.lnk"); +# endif + QFile::remove("myLinkToFile.lnk"); + QFile::remove("testfile.cpp"); + QDir dir; + dir.mkdir("myDir"); + QFile("testfile.cpp").open(QIODevice::WriteOnly); +# ifndef Q_NO_SYMLINKS_TO_DIRS + QVERIFY(QFile::link("myDir", "myLinkToDir.lnk")); +# endif + QVERIFY(QFile::link("testfile.cpp", "myLinkToFile.lnk")); + + { + QStringList entryList = QDir().entryList(); + QVERIFY(entryList.contains("myDir")); +# ifndef Q_NO_SYMLINKS_TO_DIRS + QVERIFY(entryList.contains("myLinkToDir.lnk")); +#endif + QVERIFY(entryList.contains("myLinkToFile.lnk")); + } + { + QStringList entryList = QDir().entryList(QDir::Dirs); + QVERIFY(entryList.contains("myDir")); +# ifndef Q_NO_SYMLINKS_TO_DIRS + QVERIFY(entryList.contains("myLinkToDir.lnk")); +#endif +#if defined(Q_OS_SYMBIAN) + QEXPECT_FAIL("", "OpenC stat for symlinks is buggy.", Continue); +#endif + QVERIFY(!entryList.contains("myLinkToFile.lnk")); + } + { + QStringList entryList = QDir().entryList(QDir::Dirs | QDir::NoSymLinks); + QVERIFY(entryList.contains("myDir")); + QVERIFY(!entryList.contains("myLinkToDir.lnk")); + QVERIFY(!entryList.contains("myLinkToFile.lnk")); + } + + QFile::remove("myLinkToDir.lnk"); + QFile::remove("myLinkToFile.lnk"); + QFile::remove("testfile.cpp"); + dir.rmdir("myDir"); +#endif +} + +void tst_QDir::canonicalPath_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("canonicalPath"); + QString appPath = SRCDIR; + if (appPath.isEmpty()) + appPath = QCoreApplication::instance()->applicationDirPath(); + else + appPath.chop(1); // remove the ending slash + +#if defined Q_WS_WIN + if (appPath.endsWith("release", Qt::CaseInsensitive) || appPath.endsWith("debug", Qt::CaseInsensitive)) { + QDir appDir(appPath); + QVERIFY(appDir.cdUp()); + appPath = appDir.absolutePath(); + } +#endif + + QTest::newRow("relative") << "." << appPath; + QTest::newRow("relativeSubDir") << "./testData/../testData" << appPath + "/testData"; + +#ifndef Q_WS_WIN + QTest::newRow("absPath") << appPath + "/testData/../testData" << appPath + "/testData"; +#else + QTest::newRow("absPath") << appPath + "\\testData\\..\\testData" << appPath + "/testData"; +#endif + QTest::newRow("nonexistant") << "testd" << QString(); + + QTest::newRow("rootPath") << QDir::rootPath() << QDir::rootPath(); + +#ifdef Q_OS_MAC + // On Mac OS X 10.5 and earlier, canonicalPath depends on cleanPath which + // is itself very broken and fundamentally wrong on "/./" which, this would + // exercise + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) +#endif + QTest::newRow("rootPath + ./") << QDir::rootPath().append("./") << QDir::rootPath(); + + QTest::newRow("rootPath + ../.. ") << QDir::rootPath().append("../..") << QDir::rootPath(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QTest::newRow("drive:\\") << QDir::toNativeSeparators(QDir::rootPath()) << QDir::rootPath(); + QTest::newRow("drive:\\.\\") << QDir::toNativeSeparators(QDir::rootPath().append("./")) << QDir::rootPath(); + QTest::newRow("drive:\\..\\..") << QDir::toNativeSeparators(QDir::rootPath().append("../..")) << QDir::rootPath(); + QTest::newRow("drive:") << QDir().canonicalPath().left(2) << QDir().canonicalPath(); +#endif + + QTest::newRow("resource") << ":/tst_qdir/resources/entryList" << ":/tst_qdir/resources/entryList"; +} + +void tst_QDir::canonicalPath() +{ + QDir srcPath; + if (strlen(SRCDIR) > 0) + srcPath = QDir(SRCDIR); + else + srcPath = QDir("."); + if (srcPath.absolutePath() != srcPath.canonicalPath()) + QSKIP("This test does not work if this directory path consists of symlinks.", SkipAll); + + QString oldpwd = QDir::currentPath(); + QDir::setCurrent(srcPath.absolutePath()); + + QFETCH(QString, path); + QFETCH(QString, canonicalPath); + + QDir dir(path); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QCOMPARE(dir.canonicalPath().toLower(), canonicalPath.toLower()); +#else + QCOMPARE(dir.canonicalPath(), canonicalPath); +#endif + + QDir::setCurrent(oldpwd); +} + +void tst_QDir::current_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("currentDir"); + QString appPath = SRCDIR; + if (appPath.isEmpty()) + appPath = QCoreApplication::instance()->applicationDirPath(); + else + appPath.chop(1); // remove the ending slash +#if defined Q_WS_WIN + if (appPath.endsWith("release", Qt::CaseInsensitive)) + appPath = appPath.left(appPath.length()-8); + else if (appPath.endsWith("debug", Qt::CaseInsensitive)) + appPath = appPath.left(appPath.length()-6); +#endif + + QTest::newRow("startup") << QString() << appPath; + QTest::newRow("relPath") << "testData" << appPath + "/testData"; +#ifndef Q_WS_WIN + QTest::newRow("absPath") << appPath + "/testData" << appPath + "/testData"; +#else + QTest::newRow("absPath") << appPath + "\\testData" << appPath + "/testData"; +#endif + QTest::newRow("nonexistant") << "testd" << QString(); + + QTest::newRow("parent") << ".." << appPath.left(appPath.lastIndexOf('/')); +} + +void tst_QDir::current() +{ + QString oldDir = QDir::currentPath(); + QString appPath = SRCDIR; + if (appPath.isEmpty()) + appPath = QCoreApplication::instance()->applicationDirPath(); + QDir::setCurrent(appPath); + QFETCH(QString, path); + QFETCH(QString, currentDir); + + if (!path.isEmpty()) { + bool b = QDir::setCurrent(path); + // If path is non existent, then setCurrent should be false (currentDir is empty in testData) + QVERIFY(b == !currentDir.isEmpty()); + } + if (!currentDir.isEmpty()) { + QDir newCurrent = QDir::current(); + QDir::setCurrent(oldDir); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QCOMPARE(newCurrent.absolutePath().toLower(), currentDir.toLower()); +#else + QCOMPARE(newCurrent.absolutePath(), currentDir); +#endif + } + + QDir::setCurrent(oldDir); +} + +void tst_QDir::cd_data() +{ + QTest::addColumn<QString>("startDir"); + QTest::addColumn<QString>("cdDir"); + QTest::addColumn<bool>("successExpected"); + QTest::addColumn<QString>("newDir"); + + QString appPath = QDir::currentPath(); + int index = appPath.lastIndexOf("/"); + QTest::newRow("cdUp") << QDir::currentPath() << ".." << true << appPath.left(index==0?1:index); + QTest::newRow("noChange") << QDir::currentPath() << "." << true << appPath; +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) // on windows QDir::root() is usually c:/ but cd "/" will not force it to be root + QTest::newRow("absolute") << QDir::currentPath() << "/" << true << "/"; +#else + QTest::newRow("absolute") << QDir::currentPath() << "/" << true << QDir::root().absolutePath(); +#endif + QTest::newRow("non existant") << "." << "../anonexistingdir" << false << QDir::currentPath(); + QTest::newRow("self") << "." << (QString("../") + QFileInfo(QDir::currentPath()).fileName()) << true << QDir::currentPath(); + QTest::newRow("file") << "." << "qdir.pro" << false << ""; +} + +void tst_QDir::cd() +{ + QFETCH(QString, startDir); + QFETCH(QString, cdDir); + QFETCH(bool, successExpected); + QFETCH(QString, newDir); + + QDir d = startDir; + bool notUsed = d.exists(); // make sure we cache this before so we can see if 'cd' fails to flush this + Q_UNUSED(notUsed); + QCOMPARE(d.cd(cdDir), successExpected); + if (successExpected) + QCOMPARE(d.absolutePath(), newDir); +} + +void tst_QDir::setNameFilters_data() +{ + // Effectively copied from entryList2() test + + QTest::addColumn<QString>("dirName"); // relative from current path or abs + QTest::addColumn<QStringList>("nameFilters"); + QTest::addColumn<QStringList>("expected"); + + QString appPath = SRCDIR; + if (appPath.isEmpty()) + appPath = QCoreApplication::instance()->applicationDirPath(); + if (!appPath.endsWith("/")) + appPath.append("/"); + + QTest::newRow("spaces1") << appPath + "testdir/spaces" << QStringList("*. bar") + << QStringList("foo. bar"); + QTest::newRow("spaces2") << appPath + "testdir/spaces" << QStringList("*.bar") + << QStringList("foo.bar"); + QTest::newRow("spaces3") << appPath + "testdir/spaces" << QStringList("foo.*") + << QString("foo. bar,foo.bar").split(","); + QTest::newRow("files1") << appPath + "testdir/dir" << QString("*r.cpp *.pro").split(" ") + << QString("qdir.pro,qrc_qdir.cpp,tst_qdir.cpp").split(","); + QTest::newRow("resources1") << QString(":/tst_qdir/resources/entryList") << QStringList("*.data") + << QString("file1.data,file2.data,file3.data").split(','); +} + +void tst_QDir::setNameFilters() +{ + QFETCH(QString, dirName); + QFETCH(QStringList, nameFilters); + QFETCH(QStringList, expected); + + QDir dir(dirName); + QVERIFY(dir.exists()); + + dir.setNameFilters(nameFilters); + QStringList actual = dir.entryList(); + int max = qMin(actual.count(), expected.count()); + + for (int i=0; i<max; ++i) + QCOMPARE(actual[i], expected[i]); + QCOMPARE(actual.count(), expected.count()); +} + +void +tst_QDir::cleanPath_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("data0") << "/Users/sam/troll/qt4.0//.." << "/Users/sam/troll"; + QTest::newRow("data1") << "/Users/sam////troll/qt4.0//.." << "/Users/sam/troll"; + QTest::newRow("data2") << "/" << "/"; + QTest::newRow("data3") << QDir::cleanPath("../.") << ".."; + QTest::newRow("data4") << QDir::cleanPath("../..") << "../.."; +#if !defined(Q_OS_WINCE) +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QTest::newRow("data5") << "d:\\a\\bc\\def\\.." << "d:/a/bc"; + QTest::newRow("data6") << "d:\\a\\bc\\def\\../../.." << "d:/"; +#else + QTest::newRow("data5") << "d:\\a\\bc\\def\\.." << "d:\\a\\bc\\def\\.."; + QTest::newRow("data6") << "d:\\a\\bc\\def\\../../.." << "d:\\a\\bc\\def\\../../.."; +#endif +#endif + QTest::newRow("data7") << ".//file1.txt" << "file1.txt"; + QTest::newRow("data8") << "/foo/bar/..//file1.txt" << "/foo/file1.txt"; + QTest::newRow("data9") << "//" << "/"; +#if !defined(Q_OS_WINCE) +#if defined Q_OS_WIN + QTest::newRow("data10") << "c:\\" << "c:/"; +#else + QTest::newRow("data10") << "/:/" << "/:"; +#endif +#endif + + QTest::newRow("resource0") << ":/prefix/foo.bar" << ":/prefix/foo.bar"; + QTest::newRow("resource1") << "://prefix/..//prefix/foo.bar" << ":/prefix/foo.bar"; +} + + +void +tst_QDir::cleanPath() +{ + QFETCH(QString, path); + QFETCH(QString, expected); + QString cleaned = QDir::cleanPath(path); + QCOMPARE(cleaned, expected); +} + +void tst_QDir::absoluteFilePath_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("expectedFilePath"); + + QTest::newRow("0") << "/etc" << "/passwd" << "/passwd"; + QTest::newRow("1") << "/etc" << "passwd" << "/etc/passwd"; + QTest::newRow("2") << "/" << "passwd" << "/passwd"; + QTest::newRow("3") << "relative" << "path" << QDir::currentPath() + "/relative/path"; + QTest::newRow("4") << "" << "" << QDir::currentPath(); + QTest::newRow("resource") << ":/prefix" << "foo.bar" << ":/prefix/foo.bar"; +} + +void tst_QDir::absoluteFilePath() +{ + QFETCH(QString, path); + QFETCH(QString, fileName); + QFETCH(QString, expectedFilePath); + + QDir dir(path); + QString absFilePath = dir.absoluteFilePath(fileName); + QCOMPARE(absFilePath, expectedFilePath); +} + +void tst_QDir::absolutePath_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("expectedPath"); + + QTest::newRow("0") << "/machine/share/dir1" << "/machine/share/dir1"; +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("1") << "\\machine\\share\\dir1" << "/machine/share/dir1"; +# if !defined(Q_OS_SYMBIAN) + QTest::newRow("2") << "//machine/share/dir1" << "//machine/share/dir1"; + QTest::newRow("3") << "\\\\machine\\share\\dir1" << "//machine/share/dir1"; +# endif + QTest::newRow("4") << "c:/machine/share/dir1" << "c:/machine/share/dir1"; + QTest::newRow("5") << "c:\\machine\\share\\dir1" << "c:/machine/share/dir1"; +#endif + QTest::newRow("resource") << ":/prefix/foo.bar" << ":/prefix/foo.bar"; +} + +void tst_QDir::absolutePath() +{ + QFETCH(QString, path); + QFETCH(QString, expectedPath); + + QDir dir(path); + QCOMPARE(dir.absolutePath(), expectedPath); +} + +void tst_QDir::relativeFilePath_data() +{ + QTest::addColumn<QString>("dir"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("0") << "/foo/bar" << "ding.txt" << "ding.txt"; + QTest::newRow("1") << "/foo/bar" << "ding/dong.txt" << "ding/dong.txt"; + QTest::newRow("2") << "/foo/bar" << "../ding/dong.txt" << "../ding/dong.txt"; + + QTest::newRow("3") << "/foo/bar" << "/foo/bar/ding.txt" << "ding.txt"; + QTest::newRow("4") << "/foo/bar/" << "/foo/bar/ding/dong.txt" << "ding/dong.txt"; + QTest::newRow("5") << "/foo/bar/" << "/ding/dong.txt" << "../../ding/dong.txt"; + + QTest::newRow("6") << "/" << "/ding/dong.txt" << "ding/dong.txt"; + QTest::newRow("7") << "/" << "/ding/" << "ding"; + QTest::newRow("8") << "/" << "/ding//" << "ding"; + QTest::newRow("9") << "/" << "/ding/../dong" << "dong"; + QTest::newRow("10") << "/" << "/ding/../../../../dong" << "../../../dong"; + + QTest::newRow("11") << "" << "" << ""; + +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("12") << "C:/foo/bar" << "ding" << "ding"; + QTest::newRow("13") << "C:/foo/bar" << "C:/ding/dong" << "../../ding/dong"; + QTest::newRow("14") << "C:/foo/bar" << "/ding/dong" << "../../ding/dong"; + QTest::newRow("15") << "C:/foo/bar" << "D:/ding/dong" << "D:/ding/dong"; + QTest::newRow("16") << "C:" << "C:/ding/dong" << "ding/dong"; + QTest::newRow("17") << "C:/" << "C:/ding/dong" << "ding/dong"; + QTest::newRow("18") << "C:" << "C:" << ""; + QTest::newRow("19") << "C:/" << "C:" << ""; + QTest::newRow("20") << "C:" << "C:/" << ""; + QTest::newRow("21") << "C:/" << "C:/" << ""; + QTest::newRow("22") << "C:" << "C:file.txt" << "file.txt"; + QTest::newRow("23") << "C:/" << "C:file.txt" << "file.txt"; + QTest::newRow("24") << "C:" << "C:/file.txt" << "file.txt"; + QTest::newRow("25") << "C:/" << "C:/file.txt" << "file.txt"; + QTest::newRow("26") << "C:" << "D:" << "D:"; + QTest::newRow("27") << "C:" << "D:/" << "D:/"; + QTest::newRow("28") << "C:/" << "D:" << "D:"; + QTest::newRow("29") << "C:/" << "D:/" << "D:/"; +# if !defined(Q_OS_SYMBIAN) + QTest::newRow("30") << "C:/foo/bar" << "//anotherHost/foo/bar" << "//anotherHost/foo/bar"; + QTest::newRow("31") << "//anotherHost/foo" << "//anotherHost/foo/bar" << "bar"; + QTest::newRow("32") << "//anotherHost/foo" << "bar" << "bar"; + QTest::newRow("33") << "//anotherHost/foo" << "C:/foo/bar" << "C:/foo/bar"; +# endif +#endif + + QTest::newRow("resource0") << ":/prefix" << "foo.bar" << "foo.bar"; + QTest::newRow("resource1") << ":/prefix" << ":/prefix/foo.bar" << "foo.bar"; +} + +void tst_QDir::relativeFilePath() +{ + QFETCH(QString, dir); + QFETCH(QString, path); + QFETCH(QString, expected); + + QCOMPARE(QDir(dir).relativeFilePath(path), expected); +} + +void tst_QDir::filePath_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("expectedFilePath"); + + QTest::newRow("0") << "/etc" << "/passwd" << "/passwd"; + QTest::newRow("1") << "/etc" << "passwd" << "/etc/passwd"; + QTest::newRow("2") << "/" << "passwd" << "/passwd"; + QTest::newRow("3") << "relative" << "path" << "relative/path"; + QTest::newRow("4") << "" << "" << "."; + QTest::newRow("resource") << ":/prefix" << "foo.bar" << ":/prefix/foo.bar"; +} + +void tst_QDir::filePath() +{ + QFETCH(QString, path); + QFETCH(QString, fileName); + QFETCH(QString, expectedFilePath); + + QDir dir(path); + QString absFilePath = dir.filePath(fileName); + QCOMPARE(absFilePath, expectedFilePath); +} + +void tst_QDir::remove() +{ + QFile f("remove-test"); + f.open(QIODevice::WriteOnly); + f.close(); + QDir dir; + QVERIFY(dir.remove("remove-test")); + QVERIFY(!dir.remove("/remove-test")); + QTest::ignoreMessage(QtWarningMsg, "QDir::remove: Empty or null file name"); + QVERIFY(!dir.remove("")); +} + +void tst_QDir::rename() +{ + QFile f("rename-test"); + f.open(QIODevice::WriteOnly); + f.close(); + QDir dir; + QVERIFY(dir.rename("rename-test", "rename-test-renamed")); + QVERIFY(dir.rename("rename-test-renamed", "rename-test")); +#if defined(Q_OS_MAC) + QVERIFY(!dir.rename("rename-test", "/etc/rename-test-renamed")); +#elif defined(Q_OS_SYMBIAN) + QVERIFY(!dir.rename("rename-test", "/resource/rename-test-renamed")); +#elif !defined(Q_OS_WIN) + // on windows this is possible - maybe make the test a bit better + QVERIFY(!dir.rename("rename-test", "/rename-test-renamed")); +#endif + QTest::ignoreMessage(QtWarningMsg, "QDir::rename: Empty or null file name(s)"); + QVERIFY(!dir.rename("rename-test", "")); + QTest::ignoreMessage(QtWarningMsg, "QDir::rename: Empty or null file name(s)"); + QVERIFY(!dir.rename("", "rename-test-renamed")); + QVERIFY(!dir.rename("some-file-that-does-not-exist", "rename-test-renamed")); + + QVERIFY(dir.remove("rename-test")); +} + +void tst_QDir::exists2_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("exists"); + + QTest::newRow("0") << "." << true; + QTest::newRow("1") << "/" << true; + QTest::newRow("2") << "" << false; + QTest::newRow("3") << "testData" << true; + QTest::newRow("4") << "/testData" << false; + QTest::newRow("5") << "tst_qdir.cpp" << true; + QTest::newRow("6") << "/resources.cpp" << false; + QTest::newRow("resource0") << ":/prefix/foo.bar" << false; + QTest::newRow("resource1") << ":/tst_qdir/resources/entryList/file1.data" << true; +} + +void tst_QDir::exists2() +{ + QFETCH(QString, path); + QFETCH(bool, exists); + + QString oldpwd = QDir::currentPath(); + if (strlen(SRCDIR) > 0) + QDir::setCurrent(SRCDIR); + + if (path.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, "QDir::exists: Empty or null file name"); + + QDir dir; + if (exists) + QVERIFY(dir.exists(path)); + else + QVERIFY(!dir.exists(path)); + + QDir::setCurrent(oldpwd); +} + +void tst_QDir::dirName_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("dirName"); + + QTest::newRow("slash0") << "c:/winnt/system32" << "system32"; + QTest::newRow("slash1") << "/winnt/system32" << "system32"; + QTest::newRow("slash2") << "c:/winnt/system32/kernel32.dll" << "kernel32.dll"; +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QTest::newRow("bslash0") << "c:\\winnt\\system32" << "system32"; + QTest::newRow("bslash1") << "\\winnt\\system32" << "system32"; + QTest::newRow("bslash2") << "c:\\winnt\\system32\\kernel32.dll" << "kernel32.dll"; +#endif + + QTest::newRow("resource") << ":/prefix" << "prefix"; +} + +void tst_QDir::dirName() +{ + QFETCH(QString, path); + QFETCH(QString, dirName); + + QDir dir(path); + QCOMPARE(dir.dirName(), dirName); +} + +void tst_QDir::operator_eq() +{ + QDir dir1("."); + dir1 = dir1; + dir1.setPath(".."); +} + +void tst_QDir::dotAndDotDot() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("WinCE and Symbian do not have . nor ..", SkipAll); +#else + QDir dir(QString(SRCDIR "testdir/")); + QStringList entryList = dir.entryList(QDir::Dirs); + QCOMPARE(entryList, QStringList() << QString(".") << QString("..") << QString("dir") << QString("spaces")); + entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + QCOMPARE(entryList, QStringList() << QString("dir") << QString("spaces")); +#endif +} + +void tst_QDir::homePath() +{ + QDir homeDir = QDir::home(); + QString strHome = QDir::homePath(); + + // docs say that homePath() is an absolute path + QCOMPARE(strHome, homeDir.absolutePath()); + QVERIFY(QDir::isAbsolutePath(strHome)); + +#ifdef Q_OS_UNIX + if (strHome.length() > 1) // root dir = "/" + QVERIFY(!strHome.endsWith('/')); +#elif defined(Q_OS_WIN) + if (strHome.length() > 3) // root dir = "c:/"; "//" is not really valid... + QVERIFY(!strHome.endsWith('/')); +#endif + + QStringList entries = homeDir.entryList(); + for (int i = 0; i < entries.count(); ++i) { + QFileInfo fi(QDir::homePath() + "/" + entries[i]); + QCOMPARE(fi.exists(), true); + } +} + +void tst_QDir::tempPath() +{ + QDir dir = QDir::temp(); + QString path = QDir::tempPath(); + + // docs say that tempPath() is an absolute path + QCOMPARE(path, dir.absolutePath()); + QVERIFY(QDir::isAbsolutePath(path)); + +#ifdef Q_OS_UNIX + if (path.length() > 1) // root dir = "/" + QVERIFY(!path.endsWith('/')); +#elif defined(Q_OS_WIN) + if (path.length() > 3) // root dir = "c:/"; "//" is not really valid... + QVERIFY(!path.endsWith('/')); +#endif +} + +void tst_QDir::rootPath() +{ + QDir dir = QDir::root(); + QString path = QDir::rootPath(); + + // docs say that tempPath() is an absolute path + QCOMPARE(path, dir.absolutePath()); + QVERIFY(QDir::isAbsolutePath(path)); + +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + QCOMPARE(path, QString("/")); +#endif +} + +void tst_QDir::nativeSeparators() +{ +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QCOMPARE(QDir::toNativeSeparators(QLatin1String("/")), QString("\\")); + QCOMPARE(QDir::toNativeSeparators(QLatin1String("\\")), QString("\\")); + QCOMPARE(QDir::fromNativeSeparators(QLatin1String("/")), QString("/")); + QCOMPARE(QDir::fromNativeSeparators(QLatin1String("\\")), QString("/")); +#else + QCOMPARE(QDir::toNativeSeparators(QLatin1String("/")), QString("/")); + QCOMPARE(QDir::toNativeSeparators(QLatin1String("\\")), QString("\\")); + QCOMPARE(QDir::fromNativeSeparators(QLatin1String("/")), QString("/")); + QCOMPARE(QDir::fromNativeSeparators(QLatin1String("\\")), QString("\\")); +#endif +} + +void tst_QDir::searchPaths_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("searchPathPrefixes"); + QTest::addColumn<QString>("searchPaths"); + QTest::addColumn<QString>("expectedAbsolutePath"); + + QString srcdir = SRCDIR; + if (srcdir.isEmpty()) + srcdir = QDir::currentPath(); + else + srcdir.chop(1); // remove ending slash + QString searchDir = srcdir + "/searchdir"; + + // sanity + QTest::newRow("nopath") << "picker.png" << QString() << QString() << QString(); + QTest::newRow("emptysearchpath") << "subdir1/picker.png" << QString() << QString() << QString(); + QTest::newRow("searchpathwithoutprefix") << SRCDIR "searchdir/subdir1/picker.png" << QString("searchpath") << QString("searchdir") << (searchDir+"/subdir1/picker.png"); + + // new + QTest::newRow("novalidsearchpath") << "searchpath:subdir1/picker.png" << QString() << QString() << QString(); + QTest::newRow("invalidsearchpath") << "searchpath:subdir1/picker.png" << QString("invalid") << QString("invalid") << QString(); + QTest::newRow("onlyvalidsearchpath") << "searchpath:subdir1/picker.png" << QString("searchpath") << QString(SRCDIR "searchdir") << (searchDir+"/subdir1/picker.png"); + QTest::newRow("validandinvalidsearchpath") << "searchpath:subdir1/picker.png" << QString("invalid;searchpath") << QString("invalid;" SRCDIR "searchdir") << (searchDir+"/subdir1/picker.png"); + QTest::newRow("precedence1") << "searchpath:picker.png" << QString("invalid;searchpath") << QString("invalid;" SRCDIR "searchdir/subdir1," SRCDIR "searchdir/subdir2") << (searchDir+"/subdir1/picker.png"); + QTest::newRow("precedence2") << "searchpath:picker.png" << QString("invalid;searchpath") << QString("invalid;" SRCDIR "searchdir/subdir2," SRCDIR "searchdir/subdir1") << (searchDir+"/subdir2/picker.png"); + QTest::newRow("precedence3") << "searchpath2:picker.png" << QString("searchpath1;searchpath2") << QString(SRCDIR "searchdir/subdir1;" SRCDIR "searchdir/subdir2") << (searchDir+"/subdir2/picker.png"); + + // re +} + +void tst_QDir::searchPaths() +{ + QFETCH(QString, filename); + QFETCH(QString, searchPathPrefixes); + QStringList searchPathPrefixList = searchPathPrefixes.split(";", QString::SkipEmptyParts); + QFETCH(QString, searchPaths); + QStringList searchPathsList = searchPaths.split(";", QString::SkipEmptyParts); + QFETCH(QString, expectedAbsolutePath); + bool exists = !expectedAbsolutePath.isEmpty(); + + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QDir::setSearchPaths(searchPathPrefixList.at(i), searchPathsList.at(i).split(",")); + } + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QVERIFY(QDir::searchPaths(searchPathPrefixList.at(i)) == searchPathsList.at(i).split(",")); + } + + QCOMPARE(QFile(filename).exists(), exists); + QCOMPARE(QFileInfo(filename).exists(), exists); + + if (exists) { + QCOMPARE(QFileInfo(filename).absoluteFilePath(), expectedAbsolutePath); + } + + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QDir::setSearchPaths(searchPathPrefixList.at(i), QStringList()); + } + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QVERIFY(QDir::searchPaths(searchPathPrefixList.at(i)).isEmpty()); + } + + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + foreach (QString path, searchPathsList.at(i).split(",")) { + QDir::addSearchPath(searchPathPrefixList.at(i), path); + } + } + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QVERIFY(QDir::searchPaths(searchPathPrefixList.at(i)) == searchPathsList.at(i).split(",")); + } + + QCOMPARE(QFile(filename).exists(), exists); + QCOMPARE(QFileInfo(filename).exists(), exists); + + if (exists) { + QCOMPARE(QFileInfo(filename).absoluteFilePath(), expectedAbsolutePath); + } + + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QDir::setSearchPaths(searchPathPrefixList.at(i), QStringList()); + } + for (int i = 0; i < searchPathPrefixList.count(); ++i) { + QVERIFY(QDir::searchPaths(searchPathPrefixList.at(i)).isEmpty()); + } +} + +void tst_QDir::entryListWithSearchPaths() +{ + QDir realDir(":/tst_qdir/resources/entryList"); + QVERIFY(realDir.exists()); + QVERIFY(!realDir.entryList().isEmpty()); + QVERIFY(realDir.entryList().contains("file3.data")); + + QDir::setSearchPaths("searchpath", QStringList(":/tst_qdir/resources")); + QDir dir("searchpath:entryList/"); + QCOMPARE(dir.path(), QString(":/tst_qdir/resources/entryList")); + QVERIFY(dir.exists()); + QStringList entryList = dir.entryList(); + QVERIFY(entryList.contains("file3.data")); +} + +void tst_QDir::longFileName_data() +{ + QTest::addColumn<int>("length"); + + QTest::newRow("128") << 128; + QTest::newRow("256") << 256; + QTest::newRow("512") << 512; + QTest::newRow("1024") << 1024; + QTest::newRow("2048") << 2048; + QTest::newRow("4096") << 4096; +} + +void tst_QDir::longFileName() +{ + QFETCH(int, length); + + QString fileName(length, QLatin1Char('a')); + fileName += QLatin1String(".txt"); + + QFile file(fileName); + if (!file.open(QFile::WriteOnly)) + QSKIP("Cannot create long file names", SkipAll); + + QFile file2(fileName); + QVERIFY(file2.open(QFile::ReadOnly)); + + QVERIFY(QDir().entryList().contains(fileName)); + + file.close(); + file2.close(); + + QFile::remove(fileName); +} + +void tst_QDir::updateFileLists() +{ + // Test setup + + FileSystem fs; + + QVERIFY( fs.createDirectory("update-file-lists") ); + QVERIFY( fs.createFile("update-file-lists/file1.txt") ); + QVERIFY( fs.createFile("update-file-lists/file2.doc") ); + + QVERIFY( fs.createDirectory("update-file-lists/sub-dir1") ); + QVERIFY( fs.createFile("update-file-lists/sub-dir1/file3.txt") ); + QVERIFY( fs.createFile("update-file-lists/sub-dir1/file4.doc") ); + QVERIFY( fs.createFile("update-file-lists/sub-dir1/file5.txt") ); + + QVERIFY( fs.createDirectory("update-file-lists/sub-dir2") ); + QVERIFY( fs.createFile("update-file-lists/sub-dir2/file6.txt") ); + QVERIFY( fs.createFile("update-file-lists/sub-dir2/file7.txt") ); + QVERIFY( fs.createFile("update-file-lists/sub-dir2/file8.doc") ); + QVERIFY( fs.createFile("update-file-lists/sub-dir2/file9.doc") ); + + // Actual test + + QDir dir("update-file-lists"); + +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) + //no . and .. on these OS. + QCOMPARE(dir.count(), uint(4)); + QCOMPARE(dir.entryList().size(), 4); + QCOMPARE(dir.entryInfoList().size(), 4); +#else + QCOMPARE(dir.count(), uint(6)); + QCOMPARE(dir.entryList().size(), 6); + QCOMPARE(dir.entryInfoList().size(), 6); +#endif + + dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); + + QCOMPARE(dir.entryList().size(), 4); + QCOMPARE(dir.count(), uint(4)); + QCOMPARE(dir.entryInfoList().size(), 4); + + dir.setPath("update-file-lists/sub-dir1"); + + QCOMPARE(dir.entryInfoList().size(), 3); + QCOMPARE(dir.count(), uint(3)); + QCOMPARE(dir.entryList().size(), 3); + + dir.setNameFilters(QStringList("*.txt")); + + QCOMPARE(dir.entryInfoList().size(), 2); + QCOMPARE(dir.entryList().size(), 2); + QCOMPARE(dir.count(), uint(2)); + + dir.setPath("update-file-lists"); + dir = QDir(dir.path(), + "*.txt", + QDir::Name | QDir::DirsLast, + QDir::AllEntries | QDir::AllDirs | QDir::NoDotAndDotDot); + + QCOMPARE(dir.count(), uint(3)); + QCOMPARE(dir.entryList().size(), 3); + QCOMPARE(dir.entryInfoList().size(), 3); + QCOMPARE(dir.entryList(), QStringList() << "file1.txt" << "sub-dir1" << "sub-dir2"); + + dir.setSorting(QDir::Name | QDir::DirsFirst); + + QCOMPARE(dir.count(), uint(3)); + QCOMPARE(dir.entryList().size(), 3); + QCOMPARE(dir.entryInfoList().size(), 3); + QCOMPARE(dir.entryList(), QStringList() << "sub-dir1" << "sub-dir2" << "file1.txt"); + + { + QVERIFY( fs.createFile("update-file-lists/extra-file.txt") ); + + QDir dir2(dir); + + QCOMPARE(dir2.count(), uint(3)); + QCOMPARE(dir2.entryList().size(), 3); + QCOMPARE(dir2.entryInfoList().size(), 3); + QCOMPARE(dir2.entryList(), QStringList() << "sub-dir1" << "sub-dir2" << "file1.txt"); + + dir2.refresh(); + + QCOMPARE(dir2.count(), uint(4)); + QCOMPARE(dir2.entryList().size(), 4); + QCOMPARE(dir2.entryInfoList().size(), 4); + QCOMPARE(dir2.entryList(), QStringList() << "sub-dir1" << "sub-dir2" << "extra-file.txt" << "file1.txt"); + } + + QCOMPARE(dir.count(), uint(3)); + QCOMPARE(dir.entryList().size(), 3); + QCOMPARE(dir.entryInfoList().size(), 3); + QCOMPARE(dir.entryList(), QStringList() << "sub-dir1" << "sub-dir2" << "file1.txt"); +} + +void tst_QDir::detachingOperations() +{ + QString const defaultPath("."); + QStringList const defaultNameFilters = QStringList("*"); + QDir::SortFlags const defaultSorting = QDir::Name | QDir::IgnoreCase; + QDir::Filters const defaultFilter = QDir::AllEntries; + + QString const path1(".."); + QString const path2("./foo"); + QStringList const nameFilters = QStringList(QString("*.txt")); + QDir::SortFlags const sorting = QDir::Name | QDir::DirsLast | QDir::Reversed; + QDir::Filters const filter = QDir::Writable; + + QDir dir1; + + QCOMPARE(dir1.path(), defaultPath); + QCOMPARE(dir1.filter(), defaultFilter); + QCOMPARE(dir1.nameFilters(), defaultNameFilters); + QCOMPARE(dir1.sorting(), defaultSorting); + + dir1.setPath(path1); + QCOMPARE(dir1.path(), path1); + QCOMPARE(dir1.filter(), defaultFilter); + QCOMPARE(dir1.nameFilters(), defaultNameFilters); + QCOMPARE(dir1.sorting(), defaultSorting); + + dir1.setFilter(filter); + QCOMPARE(dir1.path(), path1); + QCOMPARE(dir1.filter(), filter); + QCOMPARE(dir1.nameFilters(), defaultNameFilters); + QCOMPARE(dir1.sorting(), defaultSorting); + + dir1.setNameFilters(nameFilters); + QCOMPARE(dir1.path(), path1); + QCOMPARE(dir1.filter(), filter); + QCOMPARE(dir1.nameFilters(), nameFilters); + QCOMPARE(dir1.sorting(), defaultSorting); + + dir1.setSorting(sorting); + QCOMPARE(dir1.path(), path1); + QCOMPARE(dir1.filter(), filter); + QCOMPARE(dir1.nameFilters(), nameFilters); + QCOMPARE(dir1.sorting(), sorting); + + dir1.setPath(path2); + QCOMPARE(dir1.path(), path2); + QCOMPARE(dir1.filter(), filter); + QCOMPARE(dir1.nameFilters(), nameFilters); + QCOMPARE(dir1.sorting(), sorting); + + { + QDir dir2(dir1); + QCOMPARE(dir2.path(), path2); + QCOMPARE(dir2.filter(), filter); + QCOMPARE(dir2.nameFilters(), nameFilters); + QCOMPARE(dir2.sorting(), sorting); + } + + { + QDir dir2; + QCOMPARE(dir2.path(), defaultPath); + QCOMPARE(dir2.filter(), defaultFilter); + QCOMPARE(dir2.nameFilters(), defaultNameFilters); + QCOMPARE(dir2.sorting(), defaultSorting); + + dir2 = dir1; + QCOMPARE(dir2.path(), path2); + QCOMPARE(dir2.filter(), filter); + QCOMPARE(dir2.nameFilters(), nameFilters); + QCOMPARE(dir2.sorting(), sorting); + + dir2 = path1; + QCOMPARE(dir2.path(), path1); + QCOMPARE(dir2.filter(), filter); + QCOMPARE(dir2.nameFilters(), nameFilters); + QCOMPARE(dir2.sorting(), sorting); + } + + dir1.refresh(); + QCOMPARE(dir1.path(), path2); + QCOMPARE(dir1.filter(), filter); + QCOMPARE(dir1.nameFilters(), nameFilters); + QCOMPARE(dir1.sorting(), sorting); + + QString const currentPath = QDir::currentPath(); + QVERIFY(dir1.cd(currentPath)); + QCOMPARE(dir1.path(), currentPath); + QCOMPARE(dir1.filter(), filter); + QCOMPARE(dir1.nameFilters(), nameFilters); + QCOMPARE(dir1.sorting(), sorting); + + QVERIFY(dir1.cdUp()); + QCOMPARE(dir1.filter(), filter); + QCOMPARE(dir1.nameFilters(), nameFilters); + QCOMPARE(dir1.sorting(), sorting); +} + +void tst_QDir::testCaching() +{ + QString dirName = QString::fromLatin1("testCaching"); + QDir::current().rmdir(dirName); // cleanup a previous run. + QDir dir(dirName); + QVERIFY(!dir.exists()); + QDir::current().mkdir(dirName); + QVERIFY(QDir(dirName).exists()); // dir exists + QVERIFY(dir.exists()); // QDir doesn't cache the 'exist' between calls. +} + +void tst_QDir::isRoot_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isRoot"); + + QString test = QDir::rootPath(); + QTest::newRow(QString("rootPath " + test).toLatin1()) << test << true; + test = QDir::rootPath().append("./"); + QTest::newRow(QString("./ appended " + test).toLatin1()) << test << false; + + test = QDir(QDir::rootPath().append("./")).canonicalPath(); +#ifdef Q_OS_MAC + // On Mac OS X 10.5 and earlier, canonicalPath depends on cleanPath which + // is itself very broken and fundamentally wrong on "/./", which this would + // exercise + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) +#endif + QTest::newRow(QString("canonicalPath " + test).toLatin1()) << test << true; + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + test = QDir::rootPath().left(2); + QTest::newRow(QString("drive relative " + test).toLatin1()) << test << false; +#endif + + QTest::newRow("resources root") << ":/" << true; + QTest::newRow("resources nonroot") << ":/entrylist" << false; +} + +void tst_QDir::isRoot() +{ + QFETCH(QString, path); + QFETCH(bool, isRoot); + + QDir dir(path); + QCOMPARE(dir.isRoot(),isRoot); +} + +#ifndef QT_NO_REGEXP +void tst_QDir::match_data() +{ + QTest::addColumn<QString>("filter"); + QTest::addColumn<QString>("filename"); + QTest::addColumn<bool>("match"); + + QTest::newRow("single, matching") << "*.cpp" << "tst_qdir.cpp" << true; + QTest::newRow("single, not matching") << "*.cpp" << "tst_qdir.h" << false; + QTest::newRow("multi, matching") << "*.cpp;*.h" << "tst_qdir.cpp" << true; + QTest::newRow("multi, matching2") << "*.cpp;*.h" << "tst_qdir.h" << true; + QTest::newRow("multi, not matching") << "*.cpp;*.h" << "readme.txt" << false; +} + +void tst_QDir::match() +{ + QFETCH(QString, filter); + QFETCH(QString, filename); + QFETCH(bool, match); + + QCOMPARE(QDir::match(filter, filename), match); + QCOMPARE(QDir::match(filter.split(QLatin1Char(';')), filename), match); +} +#endif + +void tst_QDir::drives() +{ + QFileInfoList list(QDir::drives()); +#if defined(Q_OS_WIN) + QVERIFY(list.count() >= 1); //system + QLatin1Char systemdrive('c'); +#elif defined(Q_OS_SYMBIAN) + QVERIFY(list.count() >= 2); //system, rom + QLatin1Char romdrive('z'); + QLatin1Char systemdrive('a' + int(RFs::GetSystemDrive())); +#endif +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QVERIFY(list.count() <= 26); + bool foundsystem = false; +#ifdef Q_OS_SYMBIAN + bool foundrom = false; +#endif + foreach (QFileInfo fi, list) { + QCOMPARE(fi.absolutePath().size(), 3); //"x:/" + QCOMPARE(fi.absolutePath().at(1), QChar(QLatin1Char(':'))); + QCOMPARE(fi.absolutePath().at(2), QChar(QLatin1Char('/'))); + if (fi.absolutePath().at(0).toLower() == systemdrive) + foundsystem = true; +#ifdef Q_OS_SYMBIAN + if (fi.absolutePath().at(0).toLower() == romdrive) + foundrom = true; +#endif + } + QCOMPARE(foundsystem, true); +#ifdef Q_OS_SYMBIAN + QCOMPARE(foundrom, true); +#endif +#else + QCOMPARE(list.count(), 1); //root + QCOMPARE(list.at(0).absolutePath(), QLatin1String("/")); +#endif +} + +void tst_QDir::arrayOperator() +{ + QDir dir1(SRCDIR "entrylist/"); + QDir dir2(SRCDIR "entrylist/"); + + QStringList entries(dir1.entryList()); + int i = dir2.count(); + QCOMPARE(i, entries.count()); + --i; + for (;i>=0;--i) { + QCOMPARE(dir2[i], entries.at(i)); + } +} + +void tst_QDir::equalityOperator_data() +{ + QTest::addColumn<QString>("leftPath"); + QTest::addColumn<QString>("leftNameFilters"); + QTest::addColumn<int>("leftSort"); + QTest::addColumn<int>("leftFilters"); + QTest::addColumn<QString>("rightPath"); + QTest::addColumn<QString>("rightNameFilters"); + QTest::addColumn<int>("rightSort"); + QTest::addColumn<int>("rightFilters"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("same") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << true; + + QTest::newRow("relativepaths") << "entrylist/" << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << "./entrylist" << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << true; + + QTest::newRow("diff-filters") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Dirs) + << false; + + QTest::newRow("diff-sort") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.cpp" << int(QDir::Time) << int(QDir::Files) + << false; + + QTest::newRow("diff-namefilters") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files) + << SRCDIR << "*.jpg" << int(QDir::Name) << int(QDir::Files) + << false; +} + +void tst_QDir::equalityOperator() +{ + QFETCH(QString, leftPath); + QFETCH(QString, leftNameFilters); + QFETCH(int, leftSort); + QFETCH(int, leftFilters); + QFETCH(QString, rightPath); + QFETCH(QString, rightNameFilters); + QFETCH(int, rightSort); + QFETCH(int, rightFilters); + QFETCH(bool, expected); + + QDir dir1(leftPath, leftNameFilters, QDir::SortFlags(leftSort), QDir::Filters(leftFilters)); + QDir dir2(rightPath, rightNameFilters, QDir::SortFlags(rightSort), QDir::Filters(rightFilters)); + + QCOMPARE((dir1 == dir2), expected); + QCOMPARE((dir2 == dir1), expected); + QCOMPARE((dir1 != dir2), !expected); + QCOMPARE((dir2 != dir1), !expected); +} + +void tst_QDir::isRelative_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("relative"); + + QTest::newRow(".") << "./" << true; + QTest::newRow("..") << "../" << true; + QTest::newRow("content") << "entrylist/" << true; + QTest::newRow("current") << QDir::currentPath() << false; + QTest::newRow("homepath") << QDir::homePath() << false; + QTest::newRow("temppath") << QDir::tempPath() << false; + QTest::newRow("rootpath") << QDir::rootPath() << false; + foreach (QFileInfo root, QDir::drives()) { + QTest::newRow(root.absolutePath().toLocal8Bit()) << root.absolutePath() << false; + } + + QTest::newRow("resource") << ":/prefix" << false; +} + +void tst_QDir::isRelative() +{ + QFETCH(QString, path); + QFETCH(bool, relative); + + QCOMPARE(QDir(path).isRelative(), relative); +} + +void tst_QDir::isReadable() +{ + QDir dir; + + QVERIFY(dir.isReadable()); +#if defined (Q_OS_UNIX) && !defined (Q_OS_SYMBIAN) + QVERIFY(dir.mkdir("nonreadabledir")); + QVERIFY(0 == ::chmod("nonreadabledir", 0)); + QVERIFY(!QDir("nonreadabledir").isReadable()); + QVERIFY(0 == ::chmod("nonreadabledir", S_IRUSR | S_IWUSR | S_IXUSR)); + QVERIFY(dir.rmdir("nonreadabledir")); +#endif +} + +QTEST_MAIN(tst_QDir) +#include "tst_qdir.moc" + diff --git a/tests/auto/corelib/io/qdir/types/a b/tests/auto/corelib/io/qdir/types/a new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/a diff --git a/tests/auto/corelib/io/qdir/types/a.a b/tests/auto/corelib/io/qdir/types/a.a new file mode 100644 index 0000000000..7898192261 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/a.a @@ -0,0 +1 @@ +a diff --git a/tests/auto/corelib/io/qdir/types/a.b b/tests/auto/corelib/io/qdir/types/a.b new file mode 100644 index 0000000000..e61ef7b965 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/a.b @@ -0,0 +1 @@ +aa diff --git a/tests/auto/corelib/io/qdir/types/a.c b/tests/auto/corelib/io/qdir/types/a.c new file mode 100644 index 0000000000..72943a16fb --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/a.c @@ -0,0 +1 @@ +aaa diff --git a/tests/auto/corelib/io/qdir/types/b b/tests/auto/corelib/io/qdir/types/b new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/b diff --git a/tests/auto/corelib/io/qdir/types/b.a b/tests/auto/corelib/io/qdir/types/b.a new file mode 100644 index 0000000000..90b451628d --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/b.a @@ -0,0 +1 @@ +aaaaaa diff --git a/tests/auto/corelib/io/qdir/types/b.b b/tests/auto/corelib/io/qdir/types/b.b new file mode 100644 index 0000000000..5d308e1d06 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/b.b @@ -0,0 +1 @@ +aaaa diff --git a/tests/auto/corelib/io/qdir/types/b.c b/tests/auto/corelib/io/qdir/types/b.c new file mode 100644 index 0000000000..ccc3e7b48d --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/b.c @@ -0,0 +1 @@ +aaaaa diff --git a/tests/auto/corelib/io/qdir/types/c b/tests/auto/corelib/io/qdir/types/c new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/c diff --git a/tests/auto/corelib/io/qdir/types/c.a b/tests/auto/corelib/io/qdir/types/c.a new file mode 100644 index 0000000000..2b932011c2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/c.a @@ -0,0 +1 @@ +aaaaaaaaa diff --git a/tests/auto/corelib/io/qdir/types/c.b b/tests/auto/corelib/io/qdir/types/c.b new file mode 100644 index 0000000000..ea8f022358 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/c.b @@ -0,0 +1 @@ +aaaaaaaa diff --git a/tests/auto/corelib/io/qdir/types/c.c b/tests/auto/corelib/io/qdir/types/c.c new file mode 100644 index 0000000000..e5a0c33b87 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/c.c @@ -0,0 +1 @@ +aaaaaaa diff --git a/tests/auto/corelib/io/qdir/types/d.a/dummy b/tests/auto/corelib/io/qdir/types/d.a/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/d.a/dummy diff --git a/tests/auto/corelib/io/qdir/types/d.b/dummy b/tests/auto/corelib/io/qdir/types/d.b/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/d.b/dummy diff --git a/tests/auto/corelib/io/qdir/types/d.c/dummy b/tests/auto/corelib/io/qdir/types/d.c/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/d.c/dummy diff --git a/tests/auto/corelib/io/qdir/types/d/dummy b/tests/auto/corelib/io/qdir/types/d/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/d/dummy diff --git a/tests/auto/corelib/io/qdir/types/e.a/dummy b/tests/auto/corelib/io/qdir/types/e.a/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/e.a/dummy diff --git a/tests/auto/corelib/io/qdir/types/e.b/dummy b/tests/auto/corelib/io/qdir/types/e.b/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/e.b/dummy diff --git a/tests/auto/corelib/io/qdir/types/e.c/dummy b/tests/auto/corelib/io/qdir/types/e.c/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/e.c/dummy diff --git a/tests/auto/corelib/io/qdir/types/e/dummy b/tests/auto/corelib/io/qdir/types/e/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/e/dummy diff --git a/tests/auto/corelib/io/qdir/types/f.a/dummy b/tests/auto/corelib/io/qdir/types/f.a/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/f.a/dummy diff --git a/tests/auto/corelib/io/qdir/types/f.b/dummy b/tests/auto/corelib/io/qdir/types/f.b/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/f.b/dummy diff --git a/tests/auto/corelib/io/qdir/types/f.c/dummy b/tests/auto/corelib/io/qdir/types/f.c/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/f.c/dummy diff --git a/tests/auto/corelib/io/qdir/types/f/dummy b/tests/auto/corelib/io/qdir/types/f/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdir/types/f/dummy diff --git a/tests/auto/corelib/io/qdiriterator/.gitignore b/tests/auto/corelib/io/qdiriterator/.gitignore new file mode 100644 index 0000000000..cf5974f1a5 --- /dev/null +++ b/tests/auto/corelib/io/qdiriterator/.gitignore @@ -0,0 +1 @@ +tst_qdiriterator diff --git a/tests/auto/corelib/io/qdiriterator/entrylist/directory/dummy b/tests/auto/corelib/io/qdiriterator/entrylist/directory/dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdiriterator/entrylist/directory/dummy diff --git a/tests/auto/corelib/io/qdiriterator/entrylist/file b/tests/auto/corelib/io/qdiriterator/entrylist/file new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qdiriterator/entrylist/file diff --git a/tests/auto/corelib/io/qdiriterator/qdiriterator.pro b/tests/auto/corelib/io/qdiriterator/qdiriterator.pro new file mode 100644 index 0000000000..f9f5c8d664 --- /dev/null +++ b/tests/auto/corelib/io/qdiriterator/qdiriterator.pro @@ -0,0 +1,9 @@ +load(qttest_p4) +SOURCES += tst_qdiriterator.cpp +RESOURCES += qdiriterator.qrc +QT = core + +wince*mips*|wincewm50smart-msvc200*: DEFINES += WINCE_BROKEN_ITERATE=1 + +CONFIG += parallel_test +CONFIG += insignificant_test # QTBUG-21160 diff --git a/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc b/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc new file mode 100644 index 0000000000..058d474780 --- /dev/null +++ b/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>entrylist/file</file> + <file>entrylist/directory/dummy</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp new file mode 100644 index 0000000000..42ac065645 --- /dev/null +++ b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp @@ -0,0 +1,639 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qdiriterator.h> +#include <qfileinfo.h> +#include <qstringlist.h> + +#if defined(Q_OS_VXWORKS) +#define Q_NO_SYMLINKS +#endif + +#if defined(Q_OS_SYMBIAN) +#define Q_NO_SYMLINKS +#define Q_NO_SYMLINKS_TO_DIRS +#endif + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#include "../network-settings.h" +#endif + +Q_DECLARE_METATYPE(QDirIterator::IteratorFlags) +Q_DECLARE_METATYPE(QDir::Filters) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QDirIterator : public QObject +{ + Q_OBJECT + +public: + tst_QDirIterator(); + virtual ~tst_QDirIterator(); + +private: // convenience functions + QStringList createdDirectories; + QStringList createdFiles; + + QDir currentDir; + bool createDirectory(const QString &dirName) + { + if (currentDir.mkdir(dirName)) { + createdDirectories.prepend(dirName); + return true; + } + return false; + } + + enum Cleanup { DoDelete, DontDelete }; + bool createFile(const QString &fileName, Cleanup cleanup = DoDelete) + { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + if (cleanup == DoDelete) + createdFiles << fileName; + return true; + } + return false; + } + + bool createLink(const QString &destination, const QString &linkName) + { + if (QFile::link(destination, linkName)) { + createdFiles << linkName; + return true; + } + return false; + } + +private slots: + void iterateRelativeDirectory_data(); + void iterateRelativeDirectory(); + void iterateResource_data(); + void iterateResource(); + void stopLinkLoop(); + void engineWithNoIterator(); + void absoluteFilePathsFromRelativeIteratorPath(); + void recurseWithFilters() const; + void longPath(); + void task185502_dirorder(); + void relativePaths(); +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + void uncPaths_data(); + void uncPaths(); +#endif + void qtbug15421_hiddenDirs_hiddenFiles(); +}; + +tst_QDirIterator::tst_QDirIterator() +{ + QFile::remove("entrylist/entrylist1.lnk"); + QFile::remove("entrylist/entrylist2.lnk"); + QFile::remove("entrylist/entrylist3.lnk"); + QFile::remove("entrylist/entrylist4.lnk"); + QFile::remove("entrylist/directory/entrylist1.lnk"); + QFile::remove("entrylist/directory/entrylist2.lnk"); + QFile::remove("entrylist/directory/entrylist3.lnk"); + QFile::remove("entrylist/directory/entrylist4.lnk"); + + createDirectory("entrylist"); + createDirectory("entrylist/directory"); + createFile("entrylist/file", DontDelete); + createFile("entrylist/writable"); + createFile("entrylist/directory/dummy", DontDelete); + + createDirectory("recursiveDirs"); + createDirectory("recursiveDirs/dir1"); + createFile("recursiveDirs/textFileA.txt"); + createFile("recursiveDirs/dir1/aPage.html"); + createFile("recursiveDirs/dir1/textFileB.txt"); + + createDirectory("foo"); + createDirectory("foo/bar"); + createFile("foo/bar/readme.txt"); + + createDirectory("empty"); + +#ifndef Q_NO_SYMLINKS +# if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + // ### Sadly, this is a platform difference right now. + createLink("entrylist/file", "entrylist/linktofile.lnk"); +# ifndef Q_NO_SYMLINKS_TO_DIRS + createLink("entrylist/directory", "entrylist/linktodirectory.lnk"); +# endif + createLink("entrylist/nothing", "entrylist/brokenlink.lnk"); +# else + createLink("file", "entrylist/linktofile.lnk"); +# ifndef Q_NO_SYMLINKS_TO_DIRS + createLink("directory", "entrylist/linktodirectory.lnk"); +# endif + createLink("nothing", "entrylist/brokenlink.lnk"); +# endif +#endif + + createDirectory("qtbug15421_hiddenDirs_hiddenFiles"); + createFile("qtbug15421_hiddenDirs_hiddenFiles/normalFile"); + createFile("qtbug15421_hiddenDirs_hiddenFiles/.hiddenFile"); + createDirectory("qtbug15421_hiddenDirs_hiddenFiles/normalDirectory"); + createDirectory("qtbug15421_hiddenDirs_hiddenFiles/.hiddenDirectory"); + createFile("qtbug15421_hiddenDirs_hiddenFiles/normalDirectory/normalFile"); + createFile("qtbug15421_hiddenDirs_hiddenFiles/normalDirectory/.hiddenFile"); + createFile("qtbug15421_hiddenDirs_hiddenFiles/.hiddenDirectory/normalFile"); + createFile("qtbug15421_hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenFile"); + createDirectory("qtbug15421_hiddenDirs_hiddenFiles/normalDirectory/normalDirectory"); + createDirectory("qtbug15421_hiddenDirs_hiddenFiles/normalDirectory/.hiddenDirectory"); + createDirectory("qtbug15421_hiddenDirs_hiddenFiles/.hiddenDirectory/normalDirectory"); + createDirectory("qtbug15421_hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenDirectory"); +} + +tst_QDirIterator::~tst_QDirIterator() +{ + Q_FOREACH(QString fileName, createdFiles) + QFile::remove(fileName); + + Q_FOREACH(QString dirName, createdDirectories) + currentDir.rmdir(dirName); +} + +void tst_QDirIterator::iterateRelativeDirectory_data() +{ + QTest::addColumn<QString>("dirName"); // relative from current path or abs + QTest::addColumn<QDirIterator::IteratorFlags>("flags"); + QTest::addColumn<QDir::Filters>("filters"); + QTest::addColumn<QStringList>("nameFilters"); + QTest::addColumn<QStringList>("entries"); + + QTest::newRow("no flags") + << QString("entrylist") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoFilter) << QStringList("*") + << QString( +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + "entrylist/.," + "entrylist/..," +#endif + "entrylist/file," +#ifndef Q_NO_SYMLINKS + "entrylist/linktofile.lnk," +#endif + "entrylist/directory," +#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) + "entrylist/linktodirectory.lnk," +#endif + "entrylist/writable").split(','); + + QTest::newRow("NoDot") + << QString("entrylist") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::AllEntries | QDir::NoDot) << QStringList("*") + << QString( +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + "entrylist/..," +#endif + "entrylist/file," +#ifndef Q_NO_SYMLINKS + "entrylist/linktofile.lnk," +#endif + "entrylist/directory," +#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) + "entrylist/linktodirectory.lnk," +#endif + "entrylist/writable").split(','); + + QTest::newRow("NoDotDot") + << QString("entrylist") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::AllEntries | QDir::NoDotDot) << QStringList("*") + << QString( +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + "entrylist/.," +#endif + "entrylist/file," +#ifndef Q_NO_SYMLINKS + "entrylist/linktofile.lnk," +#endif + "entrylist/directory," +#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) + "entrylist/linktodirectory.lnk," +#endif + "entrylist/writable").split(','); + + QTest::newRow("NoDotAndDotDot") + << QString("entrylist") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::AllEntries | QDir::NoDotAndDotDot) << QStringList("*") + << QString( + "entrylist/file," +#ifndef Q_NO_SYMLINKS + "entrylist/linktofile.lnk," +#endif + "entrylist/directory," +#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) + "entrylist/linktodirectory.lnk," +#endif + "entrylist/writable").split(','); + + QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks") + << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories | QDirIterator::FollowSymlinks) + << QDir::Filters(QDir::NoFilter) << QStringList("*") + << QString( +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + "entrylist/.," + "entrylist/..," + "entrylist/directory/.," + "entrylist/directory/..," +#endif + "entrylist/file," +#ifndef Q_NO_SYMLINKS + "entrylist/linktofile.lnk," +#endif + "entrylist/directory," + "entrylist/directory/dummy," +#if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) + "entrylist/linktodirectory.lnk," +#endif + "entrylist/writable").split(','); + + QTest::newRow("QDir::Subdirectories / QDir::Files") + << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) + << QDir::Filters(QDir::Files) << QStringList("*") + << QString("entrylist/directory/dummy," + "entrylist/file," +#ifndef Q_NO_SYMLINKS + "entrylist/linktofile.lnk," +#endif + "entrylist/writable").split(','); + + QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks / QDir::Files") + << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories | QDirIterator::FollowSymlinks) + << QDir::Filters(QDir::Files) << QStringList("*") + << QString("entrylist/file," +#ifndef Q_NO_SYMLINKS + "entrylist/linktofile.lnk," +#endif + "entrylist/directory/dummy," + "entrylist/writable").split(','); + + QTest::newRow("empty, default") + << QString("empty") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoFilter) << QStringList("*") +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) + << QStringList(); +#else + << QString("empty/.,empty/..").split(','); +#endif + + QTest::newRow("empty, QDir::NoDotAndDotDot") + << QString("empty") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoDotAndDotDot) << QStringList("*") + << QStringList(); +} + +void tst_QDirIterator::iterateRelativeDirectory() +{ + QFETCH(QString, dirName); + QFETCH(QDirIterator::IteratorFlags, flags); + QFETCH(QDir::Filters, filters); + QFETCH(QStringList, nameFilters); + QFETCH(QStringList, entries); + + QDirIterator it(dirName, nameFilters, filters, flags); + QStringList list; + while (it.hasNext()) { + QString next = it.next(); + + QString fileName = it.fileName(); + QString filePath = it.filePath(); + QString path = it.path(); + + QFileInfo info = it.fileInfo(); + + QCOMPARE(path, dirName); + QCOMPARE(next, filePath); + + QCOMPARE(info, QFileInfo(next)); + QCOMPARE(fileName, info.fileName()); + QCOMPARE(filePath, info.filePath()); + + // Using canonical file paths for final comparison + list << info.canonicalFilePath(); + } + + // The order of items returned by QDirIterator is not guaranteed. + list.sort(); + + QStringList sortedEntries; + foreach(QString item, entries) + sortedEntries.append(QFileInfo(item).canonicalFilePath()); + sortedEntries.sort(); + + if (sortedEntries != list) { + qDebug() << "EXPECTED:" << sortedEntries; + qDebug() << "ACTUAL: " << list; + } + + QCOMPARE(list, sortedEntries); +} + +void tst_QDirIterator::iterateResource_data() +{ + QTest::addColumn<QString>("dirName"); // relative from current path or abs + QTest::addColumn<QDirIterator::IteratorFlags>("flags"); + QTest::addColumn<QDir::Filters>("filters"); + QTest::addColumn<QStringList>("nameFilters"); + QTest::addColumn<QStringList>("entries"); + + QTest::newRow("invalid") << QString::fromLatin1(":/burpaburpa") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) + << QStringList(); + QTest::newRow(":/") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) + << QString::fromLatin1(":/entrylist").split(QLatin1String(",")); + QTest::newRow(":/entrylist") << QString::fromLatin1(":/entrylist") << QDirIterator::IteratorFlags(0) + << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) + << QString::fromLatin1(":/entrylist/directory,:/entrylist/file").split(QLatin1String(",")); + QTest::newRow(":/ recursive") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) + << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) + << QString::fromLatin1(":/entrylist,:/entrylist/directory,:/entrylist/directory/dummy,:/entrylist/file").split(QLatin1String(",")); +} + +void tst_QDirIterator::iterateResource() +{ + QFETCH(QString, dirName); + QFETCH(QDirIterator::IteratorFlags, flags); + QFETCH(QDir::Filters, filters); + QFETCH(QStringList, nameFilters); + QFETCH(QStringList, entries); + + QDirIterator it(dirName, nameFilters, filters, flags); + QStringList list; + while (it.hasNext()) + list << it.next(); + + list.sort(); + QStringList sortedEntries = entries; + sortedEntries.sort(); + + if (sortedEntries != list) { + qDebug() << "EXPECTED:" << sortedEntries; + qDebug() << "ACTUAL:" << list; + } + + QCOMPARE(list, sortedEntries); +} + +void tst_QDirIterator::stopLinkLoop() +{ +#ifdef Q_OS_WIN + // ### Sadly, this is a platform difference right now. + createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/entrylist1.lnk"); + createLink("entrylist/.", "entrylist/entrylist2.lnk"); + createLink("entrylist/../entrylist/.", "entrylist/entrylist3.lnk"); + createLink("entrylist/..", "entrylist/entrylist4.lnk"); + createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/directory/entrylist1.lnk"); + createLink("entrylist/.", "entrylist/directory/entrylist2.lnk"); + createLink("entrylist/../directory/.", "entrylist/directory/entrylist3.lnk"); + createLink("entrylist/..", "entrylist/directory/entrylist4.lnk"); +#else + createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/entrylist1.lnk"); + createLink(".", "entrylist/entrylist2.lnk"); + createLink("../entrylist/.", "entrylist/entrylist3.lnk"); + createLink("..", "entrylist/entrylist4.lnk"); + createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/directory/entrylist1.lnk"); + createLink(".", "entrylist/directory/entrylist2.lnk"); + createLink("../directory/.", "entrylist/directory/entrylist3.lnk"); + createLink("..", "entrylist/directory/entrylist4.lnk"); +#endif + + QDirIterator it(QLatin1String("entrylist"), QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); + QStringList list; + int max = 200; + while (--max && it.hasNext()) + it.next(); + QVERIFY(max); + + // The goal of this test is only to ensure that the test above don't malfunction +} + +class EngineWithNoIterator : public QFSFileEngine +{ +public: + EngineWithNoIterator(const QString &fileName) + : QFSFileEngine(fileName) + { } + + QAbstractFileEngineIterator *beginEntryList(QDir::Filters, const QStringList &) + { return 0; } +}; + +class EngineWithNoIteratorHandler : public QAbstractFileEngineHandler +{ +public: + QAbstractFileEngine *create(const QString &fileName) const + { + return new EngineWithNoIterator(fileName); + } +}; + +void tst_QDirIterator::engineWithNoIterator() +{ + EngineWithNoIteratorHandler handler; + + QDir("entrylist").entryList(); + QVERIFY(true); // test that the above line doesn't crash +} + +void tst_QDirIterator::absoluteFilePathsFromRelativeIteratorPath() +{ + QDirIterator it("entrylist/", QDir::NoDotAndDotDot); + while (it.hasNext()) { + it.next(); + QVERIFY(QFileInfo(it.filePath()).absoluteFilePath().contains("entrylist")); + } +} + +void tst_QDirIterator::recurseWithFilters() const +{ + QStringList nameFilters; + nameFilters.append("*.txt"); + + QDirIterator it("recursiveDirs/", nameFilters, QDir::Files, + QDirIterator::Subdirectories); + + QSet<QString> actualEntries; + QSet<QString> expectedEntries; + expectedEntries.insert(QString::fromLatin1("recursiveDirs/dir1/textFileB.txt")); + expectedEntries.insert(QString::fromLatin1("recursiveDirs/textFileA.txt")); + + QVERIFY(it.hasNext()); + it.next(); + actualEntries.insert(it.fileInfo().filePath()); + QVERIFY(it.hasNext()); + it.next(); + actualEntries.insert(it.fileInfo().filePath()); + QVERIFY(actualEntries == expectedEntries); + + QVERIFY(!it.hasNext()); +} + +void tst_QDirIterator::longPath() +{ + QDir dir; + dir.mkdir("longpaths"); + dir.cd("longpaths"); + + QString dirName = "x"; + int n = 0; + while (dir.exists(dirName) || dir.mkdir(dirName)) { + ++n; + dirName.append('x'); +#if defined(Q_OS_WINCE) && defined(WINCE_BROKEN_ITERATE) + // Some Windows CE devices/emulators are broken. + // though one can create directories of length <= 217, + // FindNextFile only reports entries until ~ 214. + if (n >= 210) + break; +#endif + } + + QDirIterator it(dir.absolutePath(), QDir::NoDotAndDotDot|QDir::Dirs, QDirIterator::Subdirectories); + int m = 0; + while (it.hasNext()) { + ++m; + it.next(); + } + + QCOMPARE(n, m); + + dirName.chop(1); + while (dirName.length() > 0 && dir.exists(dirName) && dir.rmdir(dirName)) { + dirName.chop(1); + } + dir.cdUp(); + dir.rmdir("longpaths"); +} + +void tst_QDirIterator::task185502_dirorder() +{ + QDirIterator iterator("foo", QDirIterator::Subdirectories); + while (iterator.hasNext() && iterator.next() != "foo/bar") + { } + + QCOMPARE(iterator.filePath(), QString("foo/bar")); + QCOMPARE(iterator.fileInfo().filePath(), QString("foo/bar")); +} + +void tst_QDirIterator::relativePaths() +{ + QDirIterator iterator("*", QDirIterator::Subdirectories); + while(iterator.hasNext()) { + QCOMPARE(iterator.filePath(), QDir::cleanPath(iterator.filePath())); + } +} + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +void tst_QDirIterator::uncPaths_data() +{ + QTest::addColumn<QString>("dirName"); + QTest::newRow("uncserver") + <<QString("//" + QtNetworkSettings::winServerName()); + QTest::newRow("uncserver/testshare") + <<QString("//" + QtNetworkSettings::winServerName() + "/testshare"); + QTest::newRow("uncserver/testshare/tmp") + <<QString("//" + QtNetworkSettings::winServerName() + "/testshare/tmp"); +} +void tst_QDirIterator::uncPaths() +{ + QFETCH(QString, dirName); + QDirIterator iterator(dirName, QDir::AllEntries|QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while(iterator.hasNext()) { + iterator.next(); + QCOMPARE(iterator.filePath(), QDir::cleanPath(iterator.filePath())); + } +} +#endif + +void tst_QDirIterator::qtbug15421_hiddenDirs_hiddenFiles() +{ + // In Unix it is easy to create hidden files, but in Windows it requires + // a special call since hidden files need to be "marked" while in Unix + // anything starting by a '.' is a hidden file. + // For that reason this test is not run in Windows. +#if defined Q_OS_WIN || Q_OS_WINCE + QSKIP("To create hidden files a special call is required in Windows.", SkipAll); +#else + // Only files + { + int matches = 0; + int failures = 0; + QDirIterator di("qtbug15421_hiddenDirs_hiddenFiles", QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (di.hasNext()) { + ++matches; + QString filename = di.next(); + if (QFileInfo(filename).isDir()) + ++failures; // search was only supposed to find files + } + QCOMPARE(matches, 6); + QCOMPARE(failures, 0); + } + // Only directories + { + int matches = 0; + int failures = 0; + QDirIterator di("qtbug15421_hiddenDirs_hiddenFiles", QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (di.hasNext()) { + ++matches; + QString filename = di.next(); + if (!QFileInfo(filename).isDir()) + ++failures; // search was only supposed to find files + } + QCOMPARE(matches, 6); + QCOMPARE(failures, 0); + } +#endif // Q_OS_WIN || Q_OS_WINCE +} + +QTEST_MAIN(tst_QDirIterator) + +#include "tst_qdiriterator.moc" + diff --git a/tests/auto/corelib/io/qfile/.gitattributes b/tests/auto/corelib/io/qfile/.gitattributes new file mode 100644 index 0000000000..3be66dc5eb --- /dev/null +++ b/tests/auto/corelib/io/qfile/.gitattributes @@ -0,0 +1,2 @@ +dosfile.txt -crlf +testfile.txt -crlf
\ No newline at end of file diff --git a/tests/auto/corelib/io/qfile/.gitignore b/tests/auto/corelib/io/qfile/.gitignore new file mode 100644 index 0000000000..c508239722 --- /dev/null +++ b/tests/auto/corelib/io/qfile/.gitignore @@ -0,0 +1,8 @@ +tst_qfile +stdinprocess/stdinprocess +stdinprocess/stdinprocess.exe +readonlyfile +newfile.txt +appendfile.txt +oldfile.txt +simplefile.txt diff --git a/tests/auto/corelib/io/qfile/copy-fallback.qrc b/tests/auto/corelib/io/qfile/copy-fallback.qrc new file mode 100644 index 0000000000..864491f326 --- /dev/null +++ b/tests/auto/corelib/io/qfile/copy-fallback.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>copy-fallback.qrc</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qfile/dosfile.txt b/tests/auto/corelib/io/qfile/dosfile.txt new file mode 100644 index 0000000000..47205062e1 --- /dev/null +++ b/tests/auto/corelib/io/qfile/dosfile.txt @@ -0,0 +1,14 @@ +/dev/system/root / reiserfs acl,user_xattr 1 1
+/dev/sda1 /boot ext3 acl,user_xattr 1 2
+/dev/system/home /home reiserfs acl,user_xattr 1 2
+/dev/system/temp /tmp reiserfs acl,user_xattr 1 2
+/dev/sda2 swap swap pri=42 0 0
+devpts /dev/pts devpts mode=0620,gid=5 0 0
+proc /proc proc defaults 0 0
+usbfs /proc/bus/usb usbfs noauto 0 0
+sysfs /sys sysfs noauto 0 0
+/dev/dvd /media/dvd subfs noauto,fs=cdfss,ro,procuid,nosuid,nodev,exec,iocharset=utf8 0 0
+/dev/fd0 /media/floppy subfs noauto,fs=floppyfss,procuid,nodev,nosuid,sync 0 0
+/dev/sdb2 /media/ipod subfs noauto,rw,noexec,nosuid,nodev,sync,procuid,user,iocharset=utf8 1 2
+/dev/sdc1 /media/usbkey vfat rw,nosuid,nodev,sync,procuid,user 1 2
+
diff --git a/tests/auto/corelib/io/qfile/forCopying.txt b/tests/auto/corelib/io/qfile/forCopying.txt new file mode 100644 index 0000000000..d4143d5958 --- /dev/null +++ b/tests/auto/corelib/io/qfile/forCopying.txt @@ -0,0 +1 @@ +A basic file for copying. diff --git a/tests/auto/corelib/io/qfile/forRenaming.txt b/tests/auto/corelib/io/qfile/forRenaming.txt new file mode 100644 index 0000000000..7032162406 --- /dev/null +++ b/tests/auto/corelib/io/qfile/forRenaming.txt @@ -0,0 +1,7 @@ +---------------------------------------------------------- +DO NOT CHANGE ANY CONTENT OR ACCESS RIGHTS OF THIS FILE!!! +---------------------------------------------------------- + +This file is larger than QFile::rename()'s buffer, which is 4096 bytes. This means it is more than what is returned in its call to read(). + +112345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890234567890 diff --git a/tests/auto/corelib/io/qfile/largefile/largefile.pro b/tests/auto/corelib/io/qfile/largefile/largefile.pro new file mode 100644 index 0000000000..6407cb6b3e --- /dev/null +++ b/tests/auto/corelib/io/qfile/largefile/largefile.pro @@ -0,0 +1,8 @@ +load(qttest_p4) + +QT = core +SOURCES += tst_largefile.cpp + +wince*: SOURCES += $$QT_SOURCE_TREE/src/corelib/kernel/qfunctions_wince.cpp + +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qfile/largefile/tst_largefile.cpp b/tests/auto/corelib/io/qfile/largefile/tst_largefile.cpp new file mode 100644 index 0000000000..bf6cc688ba --- /dev/null +++ b/tests/auto/corelib/io/qfile/largefile/tst_largefile.cpp @@ -0,0 +1,538 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QTest> + +#include <QtAlgorithms> +#include <QFile> +#include <QFileInfo> +#include <qplatformdefs.h> + +#include <QDebug> + +#include <cstdlib> +#include <cstdio> + +#ifdef Q_OS_WIN + +#include <windows.h> + +#ifndef Q_OS_WINCE +#include <io.h> +#endif + +#ifndef FSCTL_SET_SPARSE +// MinGW doesn't define this. +#define FSCTL_SET_SPARSE (0x900C4) +#endif + +#endif // Q_OS_WIN + +class tst_LargeFile + : public QObject +{ + Q_OBJECT + +public: + tst_LargeFile() + : blockSize(1 << 12) + , maxSizeBits() + , fd_(-1) + , stream_(0) + { + #if defined(QT_LARGEFILE_SUPPORT) && !defined(Q_OS_MAC) + maxSizeBits = 36; // 64 GiB + #elif defined(Q_OS_MAC) + // HFS+ does not support sparse files, so we limit file size for the test + // on Mac OS. + maxSizeBits = 32; // 4 GiB + #else + maxSizeBits = 24; // 16 MiB + #endif + } + +private: + void sparseFileData(); + QByteArray const &getDataBlock(int index, qint64 position); + +private slots: + // The LargeFile test case was designed to be run in order as a single unit + + void initTestCase(); + void cleanupTestCase(); + + void init(); + void cleanup(); + + // Create and fill large file + void createSparseFile(); + void fillFileSparsely(); + void closeSparseFile(); + + // Verify file was created + void fileCreated(); + + // Positioning in large files + void filePositioning(); + void fdPositioning(); + void streamPositioning(); + + // Read data from file + void openFileForReading(); + void readFile(); + + // Map/unmap large file + void mapFile(); + void mapOffsetOverflow(); + + void closeFile() { largeFile.close(); } + + // Test data + void fillFileSparsely_data() { sparseFileData(); } + void filePositioning_data() { sparseFileData(); } + void fdPositioning_data() { sparseFileData(); } + void streamPositioning_data() { sparseFileData(); } + void readFile_data() { sparseFileData(); } + void mapFile_data() { sparseFileData(); } + +private: + const int blockSize; + int maxSizeBits; + + QFile largeFile; + + QVector<QByteArray> generatedBlocks; + + int fd_; + FILE *stream_; +}; + +/* + Convenience function to hide reinterpret_cast when copying a POD directly + into a QByteArray. + */ +template <class T> +static inline void appendRaw(QByteArray &array, T data) +{ + array.append(reinterpret_cast<char *>(&data), sizeof(T)); +} + +/* + Pad array with filler up to size. On return, array.size() returns size. + */ +static inline void topUpWith(QByteArray &array, QByteArray filler, int size) +{ + for (int i = (size - array.size()) / filler.size(); i > 0; --i) + array.append(filler); + + if (array.size() < size) { + array.append(filler.left(size - array.size())); + } +} + +/* + Generate a unique data block containing identifiable data. Unaligned, + overlapping and partial blocks should not compare equal. + */ +static inline QByteArray generateDataBlock(int blockSize, QString text, qint64 userBits = -1) +{ + QByteArray block; + block.reserve(blockSize); + + // Use of counter and randomBits means content of block will be dependent + // on the generation order. For (file-)systems that do not support sparse + // files, these can be removed so the test file can be reused and doesn't + // have to be generated for every run. + + static qint64 counter = 0; + + qint64 randomBits = ((qint64)qrand() << 32) + | ((qint64)qrand() & 0x00000000ffffffff); + + appendRaw(block, randomBits); + appendRaw(block, userBits); + appendRaw(block, counter); + appendRaw(block, (qint32)0xdeadbeef); + appendRaw(block, blockSize); + + QByteArray userContent = text.toUtf8(); + appendRaw(block, userContent.size()); + block.append(userContent); + appendRaw(block, (qint64)0); + + // size, so far + appendRaw(block, block.size()); + + QByteArray filler("0123456789"); + block.append(filler.right(10 - block.size() % 10)); + topUpWith(block, filler, blockSize - 3 * sizeof(qint64)); + + appendRaw(block, counter); + appendRaw(block, userBits); + appendRaw(block, randomBits); + + ++counter; + return block; +} + +/* + Generates data blocks the first time they are requested. Keeps copies for reuse. + */ +QByteArray const &tst_LargeFile::getDataBlock(int index, qint64 position) +{ + if (index >= generatedBlocks.size()) + generatedBlocks.resize(index + 1); + + if (generatedBlocks[index].isNull()) { + QString text = QString("Current %1-byte block (index = %2) " + "starts %3 bytes into the file '%4'.") + .arg(blockSize) + .arg(index) + .arg(position) + .arg("qt_largefile.tmp"); + + generatedBlocks[index] = generateDataBlock(blockSize, text, (qint64)1 << index); + } + + return generatedBlocks[index]; +} + +void tst_LargeFile::initTestCase() +{ + QFile file("qt_largefile.tmp"); + QVERIFY( !file.exists() || file.remove() ); +} + +void tst_LargeFile::cleanupTestCase() +{ + if (largeFile.isOpen()) + largeFile.close(); + + QFile file("qt_largefile.tmp"); + QVERIFY( !file.exists() || file.remove() ); +} + +void tst_LargeFile::init() +{ + fd_ = -1; + stream_ = 0; +} + +void tst_LargeFile::cleanup() +{ + if (-1 != fd_) + QT_CLOSE(fd_); + if (stream_) + ::fclose(stream_); +} + +void tst_LargeFile::sparseFileData() +{ + QTest::addColumn<int>("index"); + QTest::addColumn<qint64>("position"); + QTest::addColumn<QByteArray>("block"); + + QTest::newRow(QString("block[%1] @%2)") + .arg(0).arg(0) + .toLocal8Bit().constData()) + << 0 << (qint64)0 << getDataBlock(0, 0); + + // While on Linux sparse files scale well, on Windows, testing at every + // power of 2 leads to very large files. i += 4 gives us a good coverage + // without taxing too much on resources. + for (int index = 12; index <= maxSizeBits; index += 4) { + qint64 position = (qint64)1 << index; + QByteArray block = getDataBlock(index, position); + + QTest::newRow( + QString("block[%1] @%2)") + .arg(index).arg(position) + .toLocal8Bit().constData()) + << index << position << block; + } +} + +void tst_LargeFile::createSparseFile() +{ +#if defined(Q_OS_WIN32) + // On Windows platforms, we must explicitly set the file to be sparse, + // so disk space is not allocated for the full file when writing to it. + HANDLE handle = ::CreateFileA("qt_largefile.tmp", + GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); + QVERIFY( INVALID_HANDLE_VALUE != handle ); + + DWORD bytes; + if (!::DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, + &bytes, NULL)) { + QWARN("Unable to set test file as sparse. " + "Limiting test file to 16MiB."); + maxSizeBits = 24; + } + + int fd = ::_open_osfhandle((intptr_t)handle, 0); + QVERIFY( -1 != fd ); + QVERIFY( largeFile.open(fd, QIODevice::WriteOnly | QIODevice::Unbuffered) ); +#else // !Q_OS_WIN32 + largeFile.setFileName("qt_largefile.tmp"); + QVERIFY( largeFile.open(QIODevice::WriteOnly | QIODevice::Unbuffered) ); +#endif +} + +void tst_LargeFile::closeSparseFile() +{ +#if defined(Q_OS_WIN32) + int fd = largeFile.handle(); +#endif + + largeFile.close(); + +#if defined(Q_OS_WIN32) + if (-1 != fd) + ::_close(fd); +#endif +} + +void tst_LargeFile::fillFileSparsely() +{ + QFETCH( qint64, position ); + QFETCH( QByteArray, block ); + QCOMPARE( block.size(), blockSize ); + + static int lastKnownGoodIndex = 0; + struct ScopeGuard { + ScopeGuard(tst_LargeFile* test) + : this_(test) + , failed(true) + { + QFETCH( int, index ); + index_ = index; + } + + ~ScopeGuard() + { + if (failed) { + this_->maxSizeBits = lastKnownGoodIndex; + QWARN( qPrintable( + QString("QFile::error %1: '%2'. Maximum size bits reset to %3.") + .arg(this_->largeFile.error()) + .arg(this_->largeFile.errorString()) + .arg(this_->maxSizeBits)) ); + } else + lastKnownGoodIndex = qMax<int>(index_, lastKnownGoodIndex); + } + + private: + tst_LargeFile * const this_; + int index_; + + public: + bool failed; + }; + + ScopeGuard resetMaxSizeBitsOnFailure(this); + + QVERIFY( largeFile.seek(position) ); + QCOMPARE( largeFile.pos(), position ); + + QCOMPARE( largeFile.write(block), (qint64)blockSize ); + QCOMPARE( largeFile.pos(), position + blockSize ); + QVERIFY( largeFile.flush() ); + + resetMaxSizeBitsOnFailure.failed = false; +} + +void tst_LargeFile::fileCreated() +{ + QFileInfo info("qt_largefile.tmp"); + + QVERIFY( info.exists() ); + QVERIFY( info.isFile() ); + QVERIFY( info.size() >= ((qint64)1 << maxSizeBits) + blockSize ); +} + +void tst_LargeFile::filePositioning() +{ + QFETCH( qint64, position ); + + QFile file("qt_largefile.tmp"); + QVERIFY( file.open(QIODevice::ReadOnly) ); + + QVERIFY( file.seek(position) ); + QCOMPARE( file.pos(), position ); +} + +void tst_LargeFile::fdPositioning() +{ + QFETCH( qint64, position ); + + fd_ = QT_OPEN("qt_largefile.tmp", + QT_OPEN_RDONLY | QT_OPEN_LARGEFILE); + QVERIFY( -1 != fd_ ); + + QFile file; + QVERIFY( file.open(fd_, QIODevice::ReadOnly) ); + QCOMPARE( file.pos(), (qint64)0 ); + QVERIFY( file.seek(position) ); + QCOMPARE( file.pos(), position ); + + file.close(); + + QCOMPARE( QT_LSEEK(fd_, QT_OFF_T(0), SEEK_SET), QT_OFF_T(0) ); + QCOMPARE( QT_LSEEK(fd_, QT_OFF_T(position), SEEK_SET), QT_OFF_T(position) ); + + QVERIFY( file.open(fd_, QIODevice::ReadOnly) ); + QCOMPARE( QT_LSEEK(fd_, QT_OFF_T(0), SEEK_CUR), QT_OFF_T(position) ); + QCOMPARE( file.pos(), position ); + QVERIFY( file.seek(0) ); + QCOMPARE( file.pos(), (qint64)0 ); + + file.close(); + + QVERIFY( !QT_CLOSE(fd_) ); + fd_ = -1; +} + +void tst_LargeFile::streamPositioning() +{ + QFETCH( qint64, position ); + +#if defined(QT_LARGEFILE_SUPPORT) && defined(Q_CC_MSVC) && _MSC_VER < 1400 + if (position >= (qint64)1 << 31) + QSKIP("MSVC 2003 doesn't have 64 bit versions of fseek/ftell.", SkipSingle); +#endif + + stream_ = QT_FOPEN("qt_largefile.tmp", "rb"); + QVERIFY( 0 != stream_ ); + + QFile file; + QVERIFY( file.open(stream_, QIODevice::ReadOnly) ); + QCOMPARE( file.pos(), (qint64)0 ); + QVERIFY( file.seek(position) ); + QCOMPARE( file.pos(), position ); + + file.close(); + + QVERIFY( !QT_FSEEK(stream_, QT_OFF_T(0), SEEK_SET) ); + QCOMPARE( QT_FTELL(stream_), QT_OFF_T(0) ); + QVERIFY( !QT_FSEEK(stream_, QT_OFF_T(position), SEEK_SET) ); + QCOMPARE( QT_FTELL(stream_), QT_OFF_T(position) ); + + QVERIFY( file.open(stream_, QIODevice::ReadOnly) ); + QCOMPARE( QT_FTELL(stream_), QT_OFF_T(position) ); + QCOMPARE( file.pos(), position ); + QVERIFY( file.seek(0) ); + QCOMPARE( file.pos(), (qint64)0 ); + + file.close(); + + QVERIFY( !::fclose(stream_) ); + stream_ = 0; +} + +void tst_LargeFile::openFileForReading() +{ + largeFile.setFileName("qt_largefile.tmp"); + QVERIFY( largeFile.open(QIODevice::ReadOnly) ); +} + +void tst_LargeFile::readFile() +{ + QFETCH( qint64, position ); + QFETCH( QByteArray, block ); + QCOMPARE( block.size(), blockSize ); + + QVERIFY( largeFile.size() >= position + blockSize ); + + QVERIFY( largeFile.seek(position) ); + QCOMPARE( largeFile.pos(), position ); + + QCOMPARE( largeFile.read(blockSize), block ); + QCOMPARE( largeFile.pos(), position + blockSize ); +} + +void tst_LargeFile::mapFile() +{ + QFETCH( qint64, position ); + QFETCH( QByteArray, block ); + QCOMPARE( block.size(), blockSize ); + + // Keep full block mapped to facilitate OS and/or internal reuse by Qt. + uchar *baseAddress = largeFile.map(position, blockSize); + QVERIFY( baseAddress ); + QVERIFY( qEqual(block.begin(), block.end(), reinterpret_cast<char*>(baseAddress)) ); + + for (int offset = 1; offset < blockSize; ++offset) { + uchar *address = largeFile.map(position + offset, blockSize - offset); + + QVERIFY( address ); + if ( !qEqual(block.begin() + offset, block.end(), reinterpret_cast<char*>(address)) ) { + qDebug() << "Expected:" << block.toHex(); + qDebug() << "Actual :" << QByteArray(reinterpret_cast<char*>(address), blockSize).toHex(); + QVERIFY(false); + } + + QVERIFY( largeFile.unmap( address ) ); + } + + QVERIFY( largeFile.unmap( baseAddress ) ); +} + +void tst_LargeFile::mapOffsetOverflow() +{ +#if defined(Q_OS_MAC) + QSKIP("mmap'ping beyond EOF may succeed; generate bus error on access", SkipAll); +#endif + + // Out-of-range mappings should fail, and not silently clip the offset + for (int i = 50; i < 63; ++i) { + uchar *address = 0; + + address = largeFile.map(((qint64)1 << i), blockSize); + QVERIFY( !address ); + + address = largeFile.map(((qint64)1 << i) + blockSize, blockSize); + QVERIFY( !address ); + } +} + +QTEST_APPLESS_MAIN(tst_LargeFile) +#include "tst_largefile.moc" + diff --git a/tests/auto/corelib/io/qfile/noendofline.txt b/tests/auto/corelib/io/qfile/noendofline.txt new file mode 100644 index 0000000000..e120842ad9 --- /dev/null +++ b/tests/auto/corelib/io/qfile/noendofline.txt @@ -0,0 +1,3 @@ +Do not touch the content of this file. +It shows a text file +with no end-of-line-character on the last line
\ No newline at end of file diff --git a/tests/auto/corelib/io/qfile/qfile.pro b/tests/auto/corelib/io/qfile/qfile.pro new file mode 100644 index 0000000000..f41d32789a --- /dev/null +++ b/tests/auto/corelib/io/qfile/qfile.pro @@ -0,0 +1,10 @@ +TEMPLATE = subdirs +wince*|symbian:{ + SUBDIRS = test +} else { + SUBDIRS = test stdinprocess +} + +!symbian:SUBDIRS += largefile + +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qfile/qfile.qrc b/tests/auto/corelib/io/qfile/qfile.qrc new file mode 100644 index 0000000000..2c63d8afeb --- /dev/null +++ b/tests/auto/corelib/io/qfile/qfile.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/tst_qfileinfo/"> + <file>resources/</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qfile/rename-fallback.qrc b/tests/auto/corelib/io/qfile/rename-fallback.qrc new file mode 100644 index 0000000000..c8a894a61d --- /dev/null +++ b/tests/auto/corelib/io/qfile/rename-fallback.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>rename-fallback.qrc</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qfile/resources/file1.ext1 b/tests/auto/corelib/io/qfile/resources/file1.ext1 new file mode 100644 index 0000000000..e56e15bb7d --- /dev/null +++ b/tests/auto/corelib/io/qfile/resources/file1.ext1 @@ -0,0 +1 @@ +12345 diff --git a/tests/auto/corelib/io/qfile/stdinprocess/main.cpp b/tests/auto/corelib/io/qfile/stdinprocess/main.cpp new file mode 100644 index 0000000000..57a8d904f5 --- /dev/null +++ b/tests/auto/corelib/io/qfile/stdinprocess/main.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore> + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + printf("usage: stdinprocess <all|line <0|1>>\n"); + printf("echos all its input to its output.\n"); + return 1; + } + + QFile file; + + if (strcmp(argv[1], "all") == 0) { + file.open(stdin, QFile::ReadWrite); + printf("%s", file.readAll().constData()); + } else if (strcmp(argv[1], "line") == 0) { + if (strcmp(argv[2], "0") == 0) { + file.open(stdin, QFile::ReadWrite); + } else { + file.open(0, QFile::ReadWrite); + } + + char line[1024]; + while (file.readLine(line, sizeof(line)) > 0) { + printf("%s", line); + fflush(stdout); + } + } + return 0; +} diff --git a/tests/auto/corelib/io/qfile/stdinprocess/stdinprocess.pro b/tests/auto/corelib/io/qfile/stdinprocess/stdinprocess.pro new file mode 100644 index 0000000000..bf791ffc61 --- /dev/null +++ b/tests/auto/corelib/io/qfile/stdinprocess/stdinprocess.pro @@ -0,0 +1,6 @@ +SOURCES += main.cpp +QT = core +CONFIG -= app_bundle debug_and_release_target +CONFIG += console + + diff --git a/tests/auto/corelib/io/qfile/test/test.pro b/tests/auto/corelib/io/qfile/test/test.pro new file mode 100644 index 0000000000..f4ec12f874 --- /dev/null +++ b/tests/auto/corelib/io/qfile/test/test.pro @@ -0,0 +1,44 @@ +load(qttest_p4) +SOURCES += ../tst_qfile.cpp + +wince*|symbian { + QT = core gui + files.files += ..\\dosfile.txt ..\\noendofline.txt ..\\testfile.txt \ + ..\\testlog.txt ..\\two.dots.file ..\\tst_qfile.cpp \ + ..\\Makefile ..\\forCopying.txt ..\\forRenaming.txt + files.path = . + resour.files += ..\\resources\\file1.ext1 + resour.path = resources + + DEPLOYMENT += files resour +} + +wince* { + SOURCES += $$QT_SOURCE_TREE/src/corelib/kernel/qfunctions_wince.cpp # needed for QT_OPEN + DEFINES += SRCDIR=\\\"\\\" +} else:symbian { + # do not define SRCDIR at all + TARGET.EPOCHEAPSIZE = 0x100000 0x3000000 +} else { + QT = core network + DEFINES += SRCDIR=\\\"$$PWD/../\\\" +} + +RESOURCES += ../qfile.qrc ../rename-fallback.qrc ../copy-fallback.qrc + +TARGET = ../tst_qfile + +win32 { + CONFIG(debug, debug|release) { + TARGET = ../../debug/tst_qfile + } else { + TARGET = ../../release/tst_qfile + } + LIBS+=-lole32 -luuid +} + +symbian { + LIBS+=-lefsrv +} + +mac*:CONFIG+=insignificant_test diff --git a/tests/auto/corelib/io/qfile/testfile.txt b/tests/auto/corelib/io/qfile/testfile.txt new file mode 100644 index 0000000000..a5f25a118a --- /dev/null +++ b/tests/auto/corelib/io/qfile/testfile.txt @@ -0,0 +1,6 @@ +---------------------------------------------------------- +DO NOT CHANGE ANY CONTENT OR ACCESS RIGHTS OF THIS FILE!!! +---------------------------------------------------------- + +This demo file has only six lines +and a size of exactly 245 Bytes. diff --git a/tests/auto/corelib/io/qfile/testlog.txt b/tests/auto/corelib/io/qfile/testlog.txt new file mode 100644 index 0000000000..bcc7222b2f --- /dev/null +++ b/tests/auto/corelib/io/qfile/testlog.txt @@ -0,0 +1,144 @@ +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts +2006-09-29 13:50:08.349: -- File log starts_ +2006-09-29 13:50:08.349: -- File log starts diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp new file mode 100644 index 0000000000..f2031497ed --- /dev/null +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -0,0 +1,3406 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qplatformdefs.h> + +#include <QAbstractFileEngine> +#include <QFSFileEngine> +#include <QCoreApplication> +#include <QDebug> +#include <QDir> +#include <QFile> +#include <QFileInfo> +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) +#include <QHostInfo> +#endif +#include <QProcess> +#ifndef Q_OS_WIN +# include <sys/types.h> +# include <unistd.h> +#endif +#ifdef Q_OS_MAC +# include <sys/mount.h> +#elif defined(Q_OS_LINUX) +# include <sys/vfs.h> +#elif defined(Q_OS_FREEBSD) +# include <sys/param.h> +# include <sys/mount.h> +#elif defined(Q_OS_IRIX) +# include <sys/statfs.h> +#elif defined(Q_OS_WINCE) +# include <qplatformdefs.h> +# include <private/qfsfileengine_p.h> +#elif defined(Q_OS_SYMBIAN) +# include <f32file.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include "../../../network-settings.h" + +#if defined(Q_OS_SYMBIAN) +# define SRCDIR "" +#endif + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#ifndef QT_OPEN_BINARY +#define QT_OPEN_BINARY 0 +#endif + +Q_DECLARE_METATYPE(QFile::FileError) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFile : public QObject +{ + Q_OBJECT + +public: + tst_QFile(); + virtual ~tst_QFile(); + + +public slots: + void init(); + void cleanup(); +private slots: + void initTestCase(); + void cleanupTestCase(); + void exists(); + void open_data(); + void open(); + void openUnbuffered(); + void size_data(); + void size(); + void sizeNoExist(); + void seek(); + void setSize(); + void setSizeSeek(); + void atEnd(); + void readLine(); + void readLine2(); + void readLineNullInLine(); + void readAll_data(); + void readAll(); + void readAllBuffer(); + void readAllStdin(); + void readLineStdin(); + void readLineStdin_lineByLine(); + void text(); + void missingEndOfLine(); + void readBlock(); + void getch(); + void ungetChar(); + void createFile(); + void append(); + void permissions_data(); + void permissions(); + void setPermissions(); + void copy(); + void copyAfterFail(); + void copyRemovesTemporaryFile() const; + void copyShouldntOverwrite(); + void copyFallback(); + void link(); + void linkToDir(); + void absolutePathLinkToRelativePath(); + void readBrokenLink(); + void readTextFile_data(); + void readTextFile(); + void readTextFile2(); + void writeTextFile_data(); + void writeTextFile(); + /* void largeFileSupport(); */ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + void largeUncFileSupport(); +#endif + void tailFile(); + void flush(); + void bufferedRead(); + void isSequential(); + void encodeName(); + void truncate(); + void seekToPos(); + void seekAfterEndOfFile(); + void FILEReadWrite(); + void i18nFileName_data(); + void i18nFileName(); + void longFileName_data(); + void longFileName(); + void fileEngineHandler(); + void useQFileInAFileHandler(); + void getCharFF(); + void remove_and_exists(); + void removeOpenFile(); + void fullDisk(); + void writeLargeDataBlock_data(); + void writeLargeDataBlock(); + void readFromWriteOnlyFile(); + void writeToReadOnlyFile(); + void virtualFile(); + void textFile(); + void rename_data(); + void rename(); + void renameWithAtEndSpecialFile() const; + void renameFallback(); + void renameMultiple(); + void appendAndRead(); + void miscWithUncPathAsCurrentDir(); + void standarderror(); + void handle(); + void nativeHandleLeaks(); + + void readEof_data(); + void readEof(); + + void map_data(); + void map(); + void mapResource_data(); + void mapResource(); + void mapOpenMode_data(); + void mapOpenMode(); + + void openStandardStreams(); + + void resize_data(); + void resize(); + + void objectConstructors(); +#ifdef Q_OS_SYMBIAN + void platformSecurity_data(); + void platformSecurity(); +#endif + void caseSensitivity(); + + void autocloseHandle(); + + // --- Task related tests below this line + void task167217(); + + void openDirectory(); + void writeNothing(); + +public: +// disabled this test for the moment... it hangs + void invalidFile_data(); + void invalidFile(); + +private: + enum FileType { + OpenQFile, + OpenFd, + OpenStream, +#ifdef Q_OS_SYMBIAN + OpenRFile, +#endif + NumberOfFileTypes + }; + + void openStandardStreamsFileDescriptors(); + void openStandardStreamsBufferedStreams(); + + bool openFd(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags) + { + int fdMode = QT_OPEN_LARGEFILE | QT_OPEN_BINARY; + + // File will be truncated if in Write mode. + if (mode & QIODevice::WriteOnly) + fdMode |= QT_OPEN_WRONLY | QT_OPEN_TRUNC; + if (mode & QIODevice::ReadOnly) + fdMode |= QT_OPEN_RDONLY; + + fd_ = QT_OPEN(qPrintable(file.fileName()), fdMode); + + return (-1 != fd_) && file.open(fd_, mode, handleFlags); + } + + bool openStream(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags) + { + char const *streamMode = ""; + + // File will be truncated if in Write mode. + if (mode & QIODevice::WriteOnly) + streamMode = "wb+"; + else if (mode & QIODevice::ReadOnly) + streamMode = "rb"; + + stream_ = QT_FOPEN(qPrintable(file.fileName()), streamMode); + + return stream_ && file.open(stream_, mode, handleFlags); + } + +#ifdef Q_OS_SYMBIAN + bool openRFile(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags) + { + //connect file server first time + if (!rfs_.Handle() && rfs_.Connect() != KErrNone) + return false; + //symbian does not like ./ in filenames, so open by absolute path + QString fileName(QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath())); + TPtrC fn(fileName.utf16(), fileName.length()); + TInt smode = 0; + if (mode & QIODevice::WriteOnly) + smode |= EFileWrite; + if (mode & QIODevice::ReadOnly) + smode |= EFileRead; + TInt r; + if ((mode & QIODevice::Truncate) || (!(mode & QIODevice::ReadOnly) && !(mode & QIODevice::Append))) { + r = rfile_.Replace(rfs_, fn, smode); + } else { + r = rfile_.Open(rfs_, fn, smode); + if (r == KErrNotFound && (mode & QIODevice::WriteOnly)) { + r = rfile_.Create(rfs_, fn, smode); + } + } + return (r == KErrNone) && file.open(rfile_, mode, handleFlags); + } +#endif + + bool openFile(QFile &file, QIODevice::OpenMode mode, FileType type = OpenQFile, QFile::FileHandleFlags handleFlags = QFile::DontCloseHandle) + { + if (mode & QIODevice::WriteOnly && !file.exists()) + { + // Make sure the file exists + QFile createFile(file.fileName()); + if (!createFile.open(QIODevice::ReadWrite)) + return false; + } + + // Note: openFd and openStream will truncate the file if write mode. + switch (type) + { + case OpenQFile: + return file.open(mode); + + case OpenFd: + return openFd(file, mode, handleFlags); + + case OpenStream: + return openStream(file, mode, handleFlags); +#ifdef Q_OS_SYMBIAN + case OpenRFile: + return openRFile(file, mode, handleFlags); +#endif + case NumberOfFileTypes: + break; + } + + return false; + } + + void closeFile(QFile &file) + { + file.close(); + + if (-1 != fd_) + QT_CLOSE(fd_); + if (stream_) + ::fclose(stream_); +#ifdef Q_OS_SYMBIAN + if (rfile_.SubSessionHandle()) + rfile_.Close(); +#endif + + fd_ = -1; + stream_ = 0; + } + + int fd_; + FILE *stream_; +#ifdef Q_OS_SYMBIAN + RFs rfs_; + RFile rfile_; +#endif +}; + +tst_QFile::tst_QFile() +{ +} + +tst_QFile::~tst_QFile() +{ + +} + +void tst_QFile::init() +{ +// TODO: Add initialization code here. +// This will be executed immediately before each test is run. + fd_ = -1; + stream_ = 0; +} + +void tst_QFile::cleanup() +{ +// TODO: Add cleanup code here. +// This will be executed immediately after each test is run. + + // for copyFallback() + if (QFile::exists("file-copy-destination.txt")) { + QFile::setPermissions("file-copy-destination.txt", + QFile::ReadOwner | QFile::WriteOwner); + QFile::remove("file-copy-destination.txt"); + } + + // for renameFallback() + QFile::remove("file-rename-destination.txt"); + + // for copyAfterFail() + QFile::remove("file-to-be-copied.txt"); + QFile::remove("existing-file.txt"); + QFile::remove("copied-file-1.txt"); + QFile::remove("copied-file-2.txt"); + + // for renameMultiple() + QFile::remove("file-to-be-renamed.txt"); + QFile::remove("existing-file.txt"); + QFile::remove("file-renamed-once.txt"); + QFile::remove("file-renamed-twice.txt"); + + if (-1 != fd_) + QT_CLOSE(fd_); + if (stream_) + ::fclose(stream_); +} + +void tst_QFile::initTestCase() +{ + QFile::remove("noreadfile"); + + // create a file and make it read-only + QFile file("readonlyfile"); + file.open(QFile::WriteOnly); + file.write("a", 1); + file.close(); + file.setPermissions(QFile::ReadOwner); + + // create another file and make it not readable + file.setFileName("noreadfile"); + file.open(QFile::WriteOnly); + file.write("b", 1); + file.close(); + file.setPermissions(0); +} + +void tst_QFile::cleanupTestCase() +{ + // clean up the files we created + QFile::remove("readonlyfile"); + QFile::remove("noreadfile"); + QFile::remove("myLink.lnk"); + QFile::remove("appendme.txt"); + QFile::remove("createme.txt"); + QFile::remove("file.txt"); + QFile::remove("genfile.txt"); + QFile::remove("seekToPos.txt"); + QFile::remove("setsizeseek.txt"); + QFile::remove("stdfile.txt"); + QFile::remove("textfile.txt"); + QFile::remove("truncate.txt"); + QFile::remove("winfile.txt"); + QFile::remove("writeonlyfile"); + QFile::remove("largeblockfile.txt"); + QFile::remove("tst_qfile_copy.cpp"); + QFile::remove("nullinline.txt"); + QFile::remove("myLink2.lnk"); + QFile::remove("resources"); + QFile::remove("qfile_map_testfile"); + QFile::remove("readAllBuffer.txt"); + QFile::remove("qt_file.tmp"); + QFile::remove("File.txt"); +} + +//------------------------------------------ +// The 'testfile' is currently just a +// testfile. The path of this file, the +// attributes and the contents itself +// will be changed as far as we have a +// proper way to handle files in the +// testing environment. +//------------------------------------------ + +void tst_QFile::exists() +{ + QFile f( SRCDIR "testfile.txt" ); + QCOMPARE( f.exists(), (bool)TRUE ); + + QFile file("nobodyhassuchafile"); + file.remove(); + QVERIFY(!file.exists()); + + QFile file2("nobodyhassuchafile"); + QVERIFY(file2.open(QIODevice::WriteOnly)); + file2.close(); + + QVERIFY(file.exists()); + + QVERIFY(file.open(QIODevice::WriteOnly)); + file.close(); + QVERIFY(file.exists()); + + file.remove(); + QVERIFY(!file.exists()); + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QFile unc("//" + QtNetworkSettings::winServerName() + "/testshare/readme.txt"); + QVERIFY(unc.exists()); +#endif +} + +void tst_QFile::open_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<int>("mode"); + QTest::addColumn<bool>("ok"); + QTest::addColumn<QFile::FileError>("status"); + +#ifdef Q_OS_MAC + static const QString denied("Operation not permitted"); +#else + static const QString denied("Permission denied"); +#endif + QTest::newRow( "exist_readOnly" ) + << QString(SRCDIR "testfile.txt") << int(QIODevice::ReadOnly) + << (bool)TRUE << QFile::NoError; + + QTest::newRow( "exist_writeOnly" ) + << QString("readonlyfile") + << int(QIODevice::WriteOnly) + << (bool)FALSE + << QFile::OpenError; + + QTest::newRow( "exist_append" ) + << QString("readonlyfile") << int(QIODevice::Append) + << (bool)FALSE << QFile::OpenError; + + QTest::newRow( "nonexist_readOnly" ) + << QString("nonExist.txt") << int(QIODevice::ReadOnly) + << (bool)FALSE << QFile::OpenError; + + QTest::newRow("emptyfile") + << QString("") + << int(QIODevice::ReadOnly) + << (bool)FALSE + << QFile::OpenError; + + QTest::newRow("nullfile") << QString() << int(QIODevice::ReadOnly) << (bool)FALSE + << QFile::OpenError; + + QTest::newRow("two-dots") << QString(SRCDIR "two.dots.file") << int(QIODevice::ReadOnly) << (bool)TRUE + << QFile::NoError; + + QTest::newRow("readonlyfile") << QString("readonlyfile") << int(QIODevice::WriteOnly) + << (bool)FALSE << QFile::OpenError; + QTest::newRow("noreadfile") << QString("noreadfile") << int(QIODevice::ReadOnly) + << (bool)FALSE << QFile::OpenError; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QTest::newRow("//./PhysicalDrive0") << QString("//./PhysicalDrive0") << int(QIODevice::ReadOnly) + << (bool)TRUE << QFile::NoError; + QTest::newRow("uncFile") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri" << int(QIODevice::ReadOnly) + << true << QFile::NoError; +#endif +} + +void tst_QFile::open() +{ + QFETCH( QString, filename ); + QFETCH( int, mode ); + + QFile f( filename ); + + QFETCH( bool, ok ); + +#if defined(Q_OS_SYMBIAN) + if (qstrcmp(QTest::currentDataTag(), "noreadfile") == 0) + QSKIP("Symbian does not support non-readable files", SkipSingle); +#elif defined(Q_OS_UNIX) + if (::getuid() == 0) + // root and Chuck Norris don't care for file permissions. Skip. + QSKIP("Running this test as root doesn't make sense", SkipAll); +#endif + +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + QEXPECT_FAIL("noreadfile", "Windows does not currently support non-readable files.", Abort); +#endif + if (filename.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified"); + + QCOMPARE(f.open( QIODevice::OpenMode(mode) ), ok); + + QTEST( f.error(), "status" ); +} + +void tst_QFile::openUnbuffered() +{ + QFile file(SRCDIR "testfile.txt"); + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)); + char c = '\0'; + QVERIFY(file.seek(1)); + QCOMPARE(file.pos(), qint64(1)); + QVERIFY(file.getChar(&c)); + QCOMPARE(file.pos(), qint64(2)); + char d = '\0'; + QVERIFY(file.seek(3)); + QCOMPARE(file.pos(), qint64(3)); + QVERIFY(file.getChar(&d)); + QCOMPARE(file.pos(), qint64(4)); + QVERIFY(file.seek(1)); + QCOMPARE(file.pos(), qint64(1)); + char c2 = '\0'; + QVERIFY(file.getChar(&c2)); + QCOMPARE(file.pos(), qint64(2)); + QVERIFY(file.seek(3)); + QCOMPARE(file.pos(), qint64(3)); + char d2 = '\0'; + QVERIFY(file.getChar(&d2)); + QCOMPARE(file.pos(), qint64(4)); + QCOMPARE(c, c2); + QCOMPARE(d, d2); + QCOMPARE(c, '-'); + QCOMPARE(d, '-'); +} + +void tst_QFile::size_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<qint64>("size"); + + QTest::newRow( "exist01" ) << QString(SRCDIR "testfile.txt") << (qint64)245; +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + // Only test UNC on Windows./ + QTest::newRow("unc") << "//" + QString(QtNetworkSettings::winServerName() + "/testshare/test.pri") << (qint64)34; +#endif +} + +void tst_QFile::size() +{ + QFETCH( QString, filename ); + QFETCH( qint64, size ); + +#ifdef Q_WS_WINCE + filename = QFileInfo(filename).absoluteFilePath(); +#endif + + { + QFile f( filename ); + QCOMPARE( f.size(), size ); + + QVERIFY( f.open(QIODevice::ReadOnly) ); + QCOMPARE( f.size(), size ); + } + + { + QFile f; + FILE* stream = QT_FOPEN(filename.toLocal8Bit().constData(), "rb"); + QVERIFY( stream ); + QVERIFY( f.open(stream, QIODevice::ReadOnly) ); + QCOMPARE( f.size(), size ); + + f.close(); + fclose(stream); + } + + { +#ifdef Q_WS_WINCE + QSKIP("Currently low level file I/O not well supported on Windows CE", SkipSingle); +#endif + QFile f; + + int fd = QT_OPEN(filename.toLocal8Bit().constData(), QT_OPEN_RDONLY); + + QVERIFY( fd != -1 ); + QVERIFY( f.open(fd, QIODevice::ReadOnly) ); + QCOMPARE( f.size(), size ); + + f.close(); + QT_CLOSE(fd); + } +} + +void tst_QFile::sizeNoExist() +{ + QFile file("nonexist01"); + QVERIFY( !file.exists() ); + QCOMPARE( file.size(), (qint64)0 ); + QVERIFY( !file.open(QIODevice::ReadOnly) ); +} + +void tst_QFile::seek() +{ + QFile::remove("newfile.txt"); + QFile file("newfile.txt"); + file.open(QIODevice::WriteOnly); + QCOMPARE(file.size(), qint64(0)); + QCOMPARE(file.pos(), qint64(0)); + QVERIFY(file.seek(10)); + QCOMPARE(file.pos(), qint64(10)); + QCOMPARE(file.size(), qint64(0)); + file.close(); + QFile::remove("newfile.txt"); +} + +void tst_QFile::setSize() +{ + DEPENDS_ON( "size" ); + + if ( QFile::exists( "createme.txt" ) ) + QFile::remove( "createme.txt" ); + QVERIFY( !QFile::exists( "createme.txt" ) ); + + QFile f("createme.txt"); + QVERIFY(f.open(QIODevice::Truncate | QIODevice::ReadWrite)); + f.putChar('a'); + + f.seek(0); + char c = '\0'; + f.getChar(&c); + QCOMPARE(c, 'a'); + + QCOMPARE(f.size(), (qlonglong)1); + bool ok = f.resize(99); + QVERIFY(ok); + QCOMPARE(f.size(), (qlonglong)99); + + f.seek(0); + c = '\0'; + f.getChar(&c); + QCOMPARE(c, 'a'); + + QVERIFY(f.resize(1)); + QCOMPARE(f.size(), (qlonglong)1); + + f.seek(0); + c = '\0'; + f.getChar(&c); + QCOMPARE(c, 'a'); + + f.close(); + + QCOMPARE(f.size(), (qlonglong)1); + QVERIFY(f.resize(100)); + QCOMPARE(f.size(), (qlonglong)100); + QVERIFY(f.resize(50)); + QCOMPARE(f.size(), (qlonglong)50); +} + +void tst_QFile::setSizeSeek() +{ + QFile::remove("setsizeseek.txt"); + QFile f("setsizeseek.txt"); + QVERIFY(f.open(QFile::WriteOnly)); + f.write("ABCD"); + + QCOMPARE(f.pos(), qint64(4)); + f.resize(2); + QCOMPARE(f.pos(), qint64(2)); + f.resize(4); + QCOMPARE(f.pos(), qint64(2)); + f.resize(0); + QCOMPARE(f.pos(), qint64(0)); + f.resize(4); + QCOMPARE(f.pos(), qint64(0)); + + f.seek(3); + QCOMPARE(f.pos(), qint64(3)); + f.resize(2); + QCOMPARE(f.pos(), qint64(2)); +} + +void tst_QFile::atEnd() +{ + QFile f( SRCDIR "testfile.txt" ); + QVERIFY(f.open( QIODevice::ReadOnly )); + + int size = f.size(); + f.seek( size ); + + bool end = f.atEnd(); + f.close(); + QCOMPARE( end, (bool)TRUE ); +} + +void tst_QFile::readLine() +{ + QFile f( SRCDIR "testfile.txt" ); + QVERIFY(f.open( QIODevice::ReadOnly )); + + int i = 0; + char p[128]; + int foo; + while ( (foo=f.readLine( p, 128 )) > 0 ) { + ++i; + if ( i == 5 ) { + QCOMPARE( p[0], 'T' ); + QCOMPARE( p[3], 's' ); + QCOMPARE( p[11], 'i' ); + } + } + f.close(); + QCOMPARE( i, 6 ); +} + +void tst_QFile::readLine2() +{ + QFile f( SRCDIR "testfile.txt" ); + f.open( QIODevice::ReadOnly ); + + char p[128]; + QCOMPARE(f.readLine(p, 60), qlonglong(59)); + QCOMPARE(f.readLine(p, 60), qlonglong(59)); + memset(p, '@', sizeof(p)); + QCOMPARE(f.readLine(p, 60), qlonglong(59)); + + QCOMPARE(p[57], '-'); + QCOMPARE(p[58], '\n'); + QCOMPARE(p[59], '\0'); + QCOMPARE(p[60], '@'); +} + +void tst_QFile::readLineNullInLine() +{ + QFile::remove("nullinline.txt"); + QFile file("nullinline.txt"); + QVERIFY(file.open(QIODevice::ReadWrite)); + QVERIFY(file.write("linewith\0null\nanotherline\0withnull\n\0\nnull\0", 42) > 0); + QVERIFY(file.flush()); + file.reset(); + + QCOMPARE(file.readLine(), QByteArray("linewith\0null\n", 14)); + QCOMPARE(file.readLine(), QByteArray("anotherline\0withnull\n", 21)); + QCOMPARE(file.readLine(), QByteArray("\0\n", 2)); + QCOMPARE(file.readLine(), QByteArray("null\0", 5)); + QCOMPARE(file.readLine(), QByteArray()); +} + +void tst_QFile::readAll_data() +{ + QTest::addColumn<bool>("textMode"); + QTest::addColumn<QString>("fileName"); + QTest::newRow( "TextMode unixfile" ) << true << SRCDIR "testfile.txt"; + QTest::newRow( "BinaryMode unixfile" ) << false << SRCDIR "testfile.txt"; + QTest::newRow( "TextMode dosfile" ) << true << SRCDIR "dosfile.txt"; + QTest::newRow( "BinaryMode dosfile" ) << false << SRCDIR "dosfile.txt"; + QTest::newRow( "TextMode bigfile" ) << true << SRCDIR "tst_qfile.cpp"; + QTest::newRow( "BinaryMode bigfile" ) << false << SRCDIR "tst_qfile.cpp"; + QVERIFY(QFile(SRCDIR "tst_qfile.cpp").size() > 64*1024); +} + +void tst_QFile::readAll() +{ + QFETCH( bool, textMode ); + QFETCH( QString, fileName ); + + QFile file(fileName); + if (textMode) + QVERIFY(file.open(QFile::Text | QFile::ReadOnly)); + else + QVERIFY(file.open(QFile::ReadOnly)); + + QByteArray a = file.readAll(); + file.reset(); + QVERIFY(file.pos() == 0); + + QVERIFY(file.bytesAvailable() > 7); + QByteArray b = file.read(1); + char x; + file.getChar(&x); + b.append(x); + b.append(file.read(5)); + b.append(file.readAll()); + + QCOMPARE(a, b); +} + +void tst_QFile::readAllBuffer() +{ + QString fileName = QLatin1String("readAllBuffer.txt"); + + QFile::remove(fileName); + + QFile writer(fileName); + QFile reader(fileName); + + QByteArray data1("This is arguably a very simple text."); + QByteArray data2("This is surely not as simple a test."); + + QVERIFY( writer.open(QIODevice::ReadWrite | QIODevice::Unbuffered) ); + QVERIFY( reader.open(QIODevice::ReadOnly) ); + + QCOMPARE( writer.write(data1), qint64(data1.size()) ); + QVERIFY( writer.seek(0) ); + + QByteArray result; + result = reader.read(18); + QCOMPARE( result.size(), 18 ); + + QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, old version buffered in reader + QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, unbuffered in reader + + result += reader.readAll(); + + QCOMPARE( result, data1 + data2 ); + + QFile::remove(fileName); +} + +void tst_QFile::readAllStdin() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("Currently no stdin/out supported for Windows CE or Symbian", SkipAll); +#endif +#if defined(QT_NO_PROCESS) + QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll); +#else + QByteArray lotsOfData(1024, '@'); // 10 megs + + QProcess process; + process.start("stdinprocess/stdinprocess all"); + QVERIFY( process.waitForStarted() ); + for (int i = 0; i < 5; ++i) { + QTest::qWait(1000); + process.write(lotsOfData); + while (process.bytesToWrite() > 0) { + QVERIFY(process.waitForBytesWritten()); + } + } + + process.closeWriteChannel(); + process.waitForFinished(); + QCOMPARE(process.readAll().size(), lotsOfData.size() * 5); +#endif +} + +void tst_QFile::readLineStdin() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("Currently no stdin/out supported for Windows CE or Symbian", SkipAll); +#endif +#if defined(QT_NO_PROCESS) + QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll); +#else + + QByteArray lotsOfData(1024, '@'); // 10 megs + for (int i = 0; i < lotsOfData.size(); ++i) { + if ((i % 32) == 31) + lotsOfData[i] = '\n'; + else + lotsOfData[i] = char('0' + i % 32); + } + + for (int i = 0; i < 2; ++i) { + QProcess process; + process.start(QString("stdinprocess/stdinprocess line %1").arg(i), QIODevice::Text | QIODevice::ReadWrite); + for (int i = 0; i < 5; ++i) { + QTest::qWait(1000); + process.write(lotsOfData); + while (process.bytesToWrite() > 0) { + QVERIFY(process.waitForBytesWritten()); + } + } + + process.closeWriteChannel(); + QVERIFY(process.waitForFinished(5000)); + + QByteArray array = process.readAll(); + QCOMPARE(array.size(), lotsOfData.size() * 5); + for (int i = 0; i < array.size(); ++i) { + if ((i % 32) == 31) + QCOMPARE(char(array[i]), '\n'); + else + QCOMPARE(char(array[i]), char('0' + i % 32)); + } + } +#endif +} + +void tst_QFile::readLineStdin_lineByLine() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("Currently no stdin/out supported for Windows CE", SkipAll); +#endif +#if defined(QT_NO_PROCESS) + QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll); +#else + for (int i = 0; i < 2; ++i) { + QProcess process; + process.start(QString("stdinprocess/stdinprocess line %1").arg(i), QIODevice::Text | QIODevice::ReadWrite); + QVERIFY(process.waitForStarted()); + + for (int j = 0; j < 3; ++j) { + QByteArray line = "line " + QByteArray::number(j) + "\n"; + QCOMPARE(process.write(line), qint64(line.size())); + QVERIFY(process.waitForBytesWritten(2000)); + if (process.bytesAvailable() == 0) + QVERIFY(process.waitForReadyRead(2000)); + QCOMPARE(process.readAll(), line); + } + + process.closeWriteChannel(); + QVERIFY(process.waitForFinished(5000)); + } +#endif +} + +void tst_QFile::text() +{ + // dosfile.txt is a binary CRLF file + QFile file(SRCDIR "dosfile.txt"); + QVERIFY(file.open(QFile::Text | QFile::ReadOnly)); + QCOMPARE(file.readLine(), + QByteArray("/dev/system/root / reiserfs acl,user_xattr 1 1\n")); + QCOMPARE(file.readLine(), + QByteArray("/dev/sda1 /boot ext3 acl,user_xattr 1 2\n")); + file.ungetChar('\n'); + file.ungetChar('2'); + QCOMPARE(file.readLine().constData(), QByteArray("2\n").constData()); +} + +void tst_QFile::missingEndOfLine() +{ + QFile file(SRCDIR "noendofline.txt"); + QVERIFY(file.open(QFile::ReadOnly)); + + int nlines = 0; + while (!file.atEnd()) { + ++nlines; + file.readLine(); + } + + QCOMPARE(nlines, 3); +} + +void tst_QFile::readBlock() +{ + QFile f( SRCDIR "testfile.txt" ); + f.open( QIODevice::ReadOnly ); + + int length = 0; + char p[256]; + length = f.read( p, 256 ); + f.close(); + QCOMPARE( length, 245 ); + QCOMPARE( p[59], 'D' ); + QCOMPARE( p[178], 'T' ); + QCOMPARE( p[199], 'l' ); +} + +void tst_QFile::getch() +{ + QFile f( SRCDIR "testfile.txt" ); + f.open( QIODevice::ReadOnly ); + + char c; + int i = 0; + while (f.getChar(&c)) { + QCOMPARE(f.pos(), qint64(i + 1)); + if ( i == 59 ) + QCOMPARE( c, 'D' ); + ++i; + } + f.close(); + QCOMPARE( i, 245 ); +} + +void tst_QFile::ungetChar() +{ + QFile f(SRCDIR "testfile.txt"); + QVERIFY(f.open(QIODevice::ReadOnly)); + + QByteArray array = f.readLine(); + QCOMPARE(array.constData(), "----------------------------------------------------------\n"); + f.ungetChar('\n'); + + array = f.readLine(); + QCOMPARE(array.constData(), "\n"); + + f.ungetChar('\n'); + f.ungetChar('-'); + f.ungetChar('-'); + + array = f.readLine(); + QCOMPARE(array.constData(), "--\n"); + + QFile::remove("genfile.txt"); + QFile out("genfile.txt"); + QVERIFY(out.open(QIODevice::ReadWrite)); + out.write("123"); + out.seek(0); + QCOMPARE(out.readAll().constData(), "123"); + out.ungetChar('3'); + out.write("4"); + out.seek(0); + QCOMPARE(out.readAll().constData(), "124"); + out.ungetChar('4'); + out.ungetChar('2'); + out.ungetChar('1'); + char buf[3]; + QCOMPARE(out.read(buf, sizeof(buf)), qint64(3)); + QCOMPARE(buf[0], '1'); + QCOMPARE(buf[1], '2'); + QCOMPARE(buf[2], '4'); +} + +void tst_QFile::invalidFile_data() +{ + QTest::addColumn<QString>("fileName"); +#if !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) + QTest::newRow( "x11" ) << QString( "qwe//" ); +#else + QTest::newRow( "colon1" ) << QString( "fail:invalid" ); + QTest::newRow( "colon2" ) << QString( "f:ail:invalid" ); + QTest::newRow( "colon3" ) << QString( ":failinvalid" ); + QTest::newRow( "forwardslash" ) << QString( "fail/invalid" ); + QTest::newRow( "asterisk" ) << QString( "fail*invalid" ); + QTest::newRow( "questionmark" ) << QString( "fail?invalid" ); + QTest::newRow( "quote" ) << QString( "fail\"invalid" ); + QTest::newRow( "lt" ) << QString( "fail<invalid" ); + QTest::newRow( "gt" ) << QString( "fail>invalid" ); + QTest::newRow( "pipe" ) << QString( "fail|invalid" ); +#endif +} + +void tst_QFile::invalidFile() +{ + QFETCH( QString, fileName ); + QFile f( fileName ); + QVERIFY( !f.open( QIODevice::ReadWrite ) ); +} + +void tst_QFile::createFile() +{ + if ( QFile::exists( "createme.txt" ) ) + QFile::remove( "createme.txt" ); + QVERIFY( !QFile::exists( "createme.txt" ) ); + + QFile f( "createme.txt" ); + QVERIFY( f.open( QIODevice::WriteOnly ) ); + f.close(); + QVERIFY( QFile::exists( "createme.txt" ) ); +} + +void tst_QFile::append() +{ + const QString name("appendme.txt"); + if (QFile::exists(name)) + QFile::remove(name); + QVERIFY(!QFile::exists(name)); + + QFile f(name); + QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate)); + f.putChar('a'); + f.close(); + + QVERIFY(f.open(QIODevice::Append)); + QVERIFY(f.pos() == 1); + f.putChar('a'); + f.close(); + QCOMPARE(int(f.size()), 2); +} + +void tst_QFile::permissions_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<uint>("perms"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("data0") << QCoreApplication::instance()->applicationFilePath() << uint(QFile::ExeUser) << true; + QTest::newRow("data1") << SRCDIR "tst_qfile.cpp" << uint(QFile::ReadUser) << true; +// QTest::newRow("data2") << "tst_qfile.cpp" << int(QFile::WriteUser) << false; + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ReadUser) << true; + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::WriteUser) << false; + QTest::newRow("resource3") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ExeUser) << false; +} + +void tst_QFile::permissions() +{ +#if defined(Q_OS_SYMBIAN) + if (qstrcmp(QTest::currentDataTag(), "data0") == 0) + QSKIP("Symbian does not have execution permissions", SkipSingle); +#endif + QFETCH(QString, file); + QFETCH(uint, perms); + QFETCH(bool, expected); + QFile f(file); + QCOMPARE(((f.permissions() & perms) == QFile::Permissions(perms)), expected); + QCOMPARE(((QFile::permissions(file) & perms) == QFile::Permissions(perms)), expected); +} + +void tst_QFile::setPermissions() +{ + DEPENDS_ON( "permissions" ); //if that doesn't work... + + if ( QFile::exists( "createme.txt" ) ) + QFile::remove( "createme.txt" ); + QVERIFY( !QFile::exists( "createme.txt" ) ); + + QFile f("createme.txt"); + QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate)); + f.putChar('a'); + f.close(); + + QFile::Permissions perms(QFile::WriteUser | QFile::ReadUser); + QVERIFY(f.setPermissions(perms)); + QVERIFY((f.permissions() & perms) == perms); + +} + +void tst_QFile::copy() +{ + QFile::setPermissions("tst_qfile_copy.cpp", QFile::WriteUser); + QFile::remove("tst_qfile_copy.cpp"); + QFile::remove("test2"); + QVERIFY(QFile::copy(SRCDIR "tst_qfile.cpp", "tst_qfile_copy.cpp")); + QFile in1(SRCDIR "tst_qfile.cpp"), in2("tst_qfile_copy.cpp"); + QVERIFY(in1.open(QFile::ReadOnly)); + QVERIFY(in2.open(QFile::ReadOnly)); + QByteArray data1 = in1.readAll(), data2 = in2.readAll(); + QCOMPARE(data1, data2); + QFile::remove( "main_copy.cpp" ); + + QFile::copy(QDir::currentPath(), QDir::currentPath() + QLatin1String("/test2")); +} + +void tst_QFile::copyAfterFail() +{ + QFile file1("file-to-be-copied.txt"); + QFile file2("existing-file.txt"); + + QVERIFY(file1.open(QIODevice::ReadWrite) && "(test-precondition)"); + QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)"); + file2.close(); + QVERIFY(!QFile::exists("copied-file-1.txt") && "(test-precondition)"); + QVERIFY(!QFile::exists("copied-file-2.txt") && "(test-precondition)"); + + QVERIFY(!file1.copy("existing-file.txt")); + QCOMPARE(file1.error(), QFile::CopyError); + + QVERIFY(file1.copy("copied-file-1.txt")); + QVERIFY(!file1.isOpen()); + QCOMPARE(file1.error(), QFile::NoError); + + QVERIFY(!file1.copy("existing-file.txt")); + QCOMPARE(file1.error(), QFile::CopyError); + + QVERIFY(file1.copy("copied-file-2.txt")); + QVERIFY(!file1.isOpen()); + QCOMPARE(file1.error(), QFile::NoError); + + QVERIFY(QFile::exists("copied-file-1.txt")); + QVERIFY(QFile::exists("copied-file-2.txt")); + + QVERIFY(QFile::remove("file-to-be-copied.txt") && "(test-cleanup)"); + QVERIFY(QFile::remove("existing-file.txt") && "(test-cleanup)"); + QVERIFY(QFile::remove("copied-file-1.txt") && "(test-cleanup)"); + QVERIFY(QFile::remove("copied-file-2.txt") && "(test-cleanup)"); +} + +void tst_QFile::copyRemovesTemporaryFile() const +{ + const QString newName(QLatin1String("copyRemovesTemporaryFile")); + QVERIFY(QFile::copy(SRCDIR "forCopying.txt", newName)); + + QVERIFY(!QFile::exists(QLatin1String( SRCDIR "qt_temp.XXXXXX"))); + QVERIFY(QFile::remove(newName)); +} + +void tst_QFile::copyShouldntOverwrite() +{ + // Copy should not overwrite existing files. + QFile::remove("tst_qfile.cpy"); + QFile file(SRCDIR "tst_qfile.cpp"); + QVERIFY(file.copy("tst_qfile.cpy")); +#if defined(Q_OS_SYMBIAN) + bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteUser); +#else + bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteOther); +#endif + QVERIFY(ok); + QVERIFY(!file.copy("tst_qfile.cpy")); + QFile::remove("tst_qfile.cpy"); +} + +void tst_QFile::copyFallback() +{ + // Using a resource file to trigger QFile::copy's fallback handling + QFile file(":/copy-fallback.qrc"); + QFile::remove("file-copy-destination.txt"); + + QVERIFY2(file.exists(), "test precondition"); + QVERIFY2(!QFile::exists("file-copy-destination.txt"), "test precondition"); + + // Fallback copy of closed file. + QVERIFY(file.copy("file-copy-destination.txt")); + QVERIFY(QFile::exists("file-copy-destination.txt")); + QVERIFY(!file.isOpen()); + +#ifdef Q_WS_WINCE + // Need to reset permissions on Windows to be able to delete + QVERIFY(QFile::setPermissions("file-copy-destination.txt", + QFile::WriteOther)); +#else + // Need to reset permissions on Windows to be able to delete + QVERIFY(QFile::setPermissions("file-copy-destination.txt", + QFile::ReadOwner | QFile::WriteOwner)); +#endif + QVERIFY(QFile::remove("file-copy-destination.txt")); + + // Fallback copy of open file. + QVERIFY(file.open(QIODevice::ReadOnly)); + QVERIFY(file.copy("file-copy-destination.txt")); + QVERIFY(QFile::exists("file-copy-destination.txt")); + QVERIFY(!file.isOpen()); + + file.close(); + QFile::remove("file-copy-destination.txt"); +} + +#ifdef Q_OS_WIN +#include <objbase.h> +#include <shlobj.h> +#endif + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +static QString getWorkingDirectoryForLink(const QString &linkFileName) +{ + bool neededCoInit = false; + QString ret; + + IShellLink *psl; + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); + if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized + neededCoInit = true; + CoInitialize(NULL); + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl); + } + + if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface. + IPersistFile *ppf; + hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); + if (SUCCEEDED(hres)) { + hres = ppf->Load((LPOLESTR)linkFileName.utf16(), STGM_READ); + //The original path of the link is retrieved. If the file/folder + //was moved, the return value still have the old path. + if(SUCCEEDED(hres)) { + wchar_t szGotPath[MAX_PATH]; + if (psl->GetWorkingDirectory(szGotPath, MAX_PATH) == NOERROR) + ret = QString::fromWCharArray(szGotPath); + } + ppf->Release(); + } + psl->Release(); + } + + if (neededCoInit) { + CoUninitialize(); + } + + return ret; +} +#endif + +void tst_QFile::link() +{ +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support links", SkipAll); +#endif + QFile::remove("myLink.lnk"); + + QFileInfo info1(SRCDIR "tst_qfile.cpp"); + QString referenceTarget = QDir::cleanPath(info1.absoluteFilePath()); + + QVERIFY(QFile::link(SRCDIR "tst_qfile.cpp", "myLink.lnk")); + + QFileInfo info2("myLink.lnk"); + QVERIFY(info2.isSymLink()); + QCOMPARE(info2.symLinkTarget(), referenceTarget); + + QFile link("myLink.lnk"); + QVERIFY(link.open(QIODevice::ReadOnly)); + QCOMPARE(link.symLinkTarget(), referenceTarget); + link.close(); + + QCOMPARE(QFile::symLinkTarget("myLink.lnk"), referenceTarget); + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QString wd = getWorkingDirectoryForLink(info2.absoluteFilePath()); + QCOMPARE(QDir::fromNativeSeparators(wd), QDir::cleanPath(info1.absolutePath())); +#endif + + QVERIFY(QFile::remove(info2.absoluteFilePath())); +} + +void tst_QFile::linkToDir() +{ +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support linking to directories", SkipAll); +#endif + QFile::remove("myLinkToDir.lnk"); + QDir dir; + dir.mkdir("myDir"); + QFileInfo info1("myDir"); + QVERIFY(QFile::link("myDir", "myLinkToDir.lnk")); + QFileInfo info2("myLinkToDir.lnk"); +#if !(defined Q_OS_HPUX && defined(__ia64)) + // absurd HP-UX filesystem bug on gravlaks - checking if a symlink + // resolves or not alters the file system to make the broken symlink + // later fail... + QVERIFY(info2.isSymLink()); +#endif + QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath()); + QVERIFY(QFile::remove(info2.absoluteFilePath())); + QFile::remove("myLinkToDir.lnk"); + dir.rmdir("myDir"); +} + +void tst_QFile::absolutePathLinkToRelativePath() +{ +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support links", SkipAll); +#endif + QFile::remove("myDir/test.txt"); + QFile::remove("myDir/myLink.lnk"); + QDir dir; + dir.mkdir("myDir"); + QFile("myDir/test.txt").open(QFile::WriteOnly); + +#ifdef Q_OS_WIN + QVERIFY(QFile::link("test.txt", "myDir/myLink.lnk")); +#else + QVERIFY(QFile::link("myDir/test.txt", "myDir/myLink.lnk")); +#endif + QEXPECT_FAIL("", "Symlinking using relative paths is currently different on Windows and Unix/Symbian", Continue); + QCOMPARE(QFileInfo(QFile(QFileInfo("myDir/myLink.lnk").absoluteFilePath()).symLinkTarget()).absoluteFilePath(), + QFileInfo("myDir/test.txt").absoluteFilePath()); + + QFile::remove("myDir/test.txt"); + QFile::remove("myDir/myLink.lnk"); + dir.rmdir("myDir"); +} + +void tst_QFile::readBrokenLink() +{ +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support links", SkipAll); +#endif + QFile::remove("myLink2.lnk"); + QFileInfo info1("file12"); +#if defined(Q_OS_SYMBIAN) + // In Symbian can't link to nonexisting file directly, so create the file temporarily + QFile tempFile("file12"); + tempFile.open(QIODevice::WriteOnly); + tempFile.link("myLink2.lnk"); + tempFile.remove(); +#else + QVERIFY(QFile::link("file12", "myLink2.lnk")); +#endif + QFileInfo info2("myLink2.lnk"); + QVERIFY(info2.isSymLink()); + QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath()); + QVERIFY(QFile::remove(info2.absoluteFilePath())); + +#if !defined(Q_OS_SYMBIAN) + QVERIFY(QFile::link("ole/..", "myLink2.lnk")); + QCOMPARE(QFileInfo("myLink2.lnk").symLinkTarget(), QDir::currentPath()); +#endif +} + +void tst_QFile::readTextFile_data() +{ + QTest::addColumn<QByteArray>("in"); + QTest::addColumn<QByteArray>("out"); + + QTest::newRow("empty") << QByteArray() << QByteArray(); + QTest::newRow("a") << QByteArray("a") << QByteArray("a"); + QTest::newRow("a\\rb") << QByteArray("a\rb") << QByteArray("ab"); + QTest::newRow("\\n") << QByteArray("\n") << QByteArray("\n"); + QTest::newRow("\\r\\n") << QByteArray("\r\n") << QByteArray("\n"); + QTest::newRow("\\r") << QByteArray("\r") << QByteArray(); + QTest::newRow("twolines") << QByteArray("Hello\r\nWorld\r\n") << QByteArray("Hello\nWorld\n"); + QTest::newRow("twolines no endline") << QByteArray("Hello\r\nWorld") << QByteArray("Hello\nWorld"); +} + +void tst_QFile::readTextFile() +{ + QFETCH(QByteArray, in); + QFETCH(QByteArray, out); + + QFile winfile("winfile.txt"); + QVERIFY(winfile.open(QFile::WriteOnly | QFile::Truncate)); + winfile.write(in); + winfile.close(); + + QVERIFY(winfile.open(QFile::ReadOnly)); + QCOMPARE(winfile.readAll(), in); + winfile.close(); + + QVERIFY(winfile.open(QFile::ReadOnly | QFile::Text)); + QCOMPARE(winfile.readAll(), out); +} + +void tst_QFile::readTextFile2() +{ + { + QFile file(SRCDIR "testlog.txt"); + QVERIFY(file.open(QIODevice::ReadOnly)); + file.read(4097); + } + + { + QFile file(SRCDIR "testlog.txt"); + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); + file.read(4097); + } +} + +void tst_QFile::writeTextFile_data() +{ + QTest::addColumn<QByteArray>("in"); + + QTest::newRow("empty") << QByteArray(); + QTest::newRow("a") << QByteArray("a"); + QTest::newRow("a\\rb") << QByteArray("a\rb"); + QTest::newRow("\\n") << QByteArray("\n"); + QTest::newRow("\\r\\n") << QByteArray("\r\n"); + QTest::newRow("\\r") << QByteArray("\r"); + QTest::newRow("twolines crlf") << QByteArray("Hello\r\nWorld\r\n"); + QTest::newRow("twolines crlf no endline") << QByteArray("Hello\r\nWorld"); + QTest::newRow("twolines lf") << QByteArray("Hello\nWorld\n"); + QTest::newRow("twolines lf no endline") << QByteArray("Hello\nWorld"); + QTest::newRow("mixed") << QByteArray("this\nis\r\na\nmixed\r\nfile\n"); +} + +void tst_QFile::writeTextFile() +{ + QFETCH(QByteArray, in); + + QFile file("textfile.txt"); + QVERIFY(file.open(QFile::WriteOnly | QFile::Truncate | QFile::Text)); + QByteArray out = in; +#ifdef Q_OS_WIN + out.replace('\n', "\r\n"); +#endif + QCOMPARE(file.write(in), qlonglong(in.size())); + file.close(); + + file.open(QFile::ReadOnly); + QCOMPARE(file.readAll(), out); +} + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +void tst_QFile::largeUncFileSupport() +{ + qint64 size = Q_INT64_C(8589934592); + qint64 dataOffset = Q_INT64_C(8589914592); + QByteArray knownData("LargeFile content at offset 8589914592"); + QString largeFile("//" + QtNetworkSettings::winServerName() + "/testsharelargefile/file.bin"); + + { + // 1) Native file handling. + QFile file(largeFile); + QCOMPARE(file.size(), size); + QVERIFY(file.open(QIODevice::ReadOnly)); + QCOMPARE(file.size(), size); + QVERIFY(file.seek(dataOffset)); + QCOMPARE(file.read(knownData.size()), knownData); + } + { + // 2) stdlib file handling. +#if _MSC_VER <= 1310 + QSKIP("platform SDK for MSVC 2003 does not support large files", SkipAll); +#endif + QFile file; + FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb"); + QVERIFY(file.open(fh, QIODevice::ReadOnly)); + QCOMPARE(file.size(), size); + QVERIFY(file.seek(dataOffset)); + QCOMPARE(file.read(knownData.size()), knownData); + fclose(fh); + } + { + // 3) stdio file handling. + QFile file; + FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb"); + int fd = int(_fileno(fh)); + QVERIFY(file.open(fd, QIODevice::ReadOnly)); + QCOMPARE(file.size(), size); + QVERIFY(file.seek(dataOffset)); + QCOMPARE(file.read(knownData.size()), knownData); + fclose(fh); + } +} +#endif + +void tst_QFile::tailFile() +{ + QSKIP("File change notifications are so far unsupported.", SkipAll); + + QFile file("tail.txt"); + QVERIFY(file.open(QFile::WriteOnly | QFile::Append)); + + QFile tailFile("tail.txt"); + QVERIFY(tailFile.open(QFile::ReadOnly)); + tailFile.seek(file.size()); + + QSignalSpy readSignal(&tailFile, SIGNAL(readyRead())); + + file.write("", 1); + + QTestEventLoop::instance().enterLoop(5); + + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(readSignal.count(), 1); +} + +void tst_QFile::flush() +{ + QString fileName("stdfile.txt"); + + QFile::remove(fileName); + + { + QFile file(fileName); + QVERIFY(file.open(QFile::WriteOnly)); + QCOMPARE(file.write("abc", 3),qint64(3)); + } + + { + QFile file(fileName); + QVERIFY(file.open(QFile::WriteOnly | QFile::Append)); + QCOMPARE(file.pos(), qlonglong(3)); + QCOMPARE(file.write("def", 3), qlonglong(3)); + QCOMPARE(file.pos(), qlonglong(6)); + } + + { + QFile file("stdfile.txt"); + QVERIFY(file.open(QFile::ReadOnly)); + QCOMPARE(file.readAll(), QByteArray("abcdef")); + } + + QFile::remove(fileName); +} + +void tst_QFile::bufferedRead() +{ + QFile::remove("stdfile.txt"); + + QFile file("stdfile.txt"); + QVERIFY(file.open(QFile::WriteOnly)); + file.write("abcdef"); + file.close(); + +#if defined(Q_OS_WINCE) + FILE *stdFile = fopen((QCoreApplication::applicationDirPath() + "/stdfile.txt").toAscii() , "r"); +#else + FILE *stdFile = fopen("stdfile.txt", "r"); +#endif + QVERIFY(stdFile); + char c; + QCOMPARE(int(fread(&c, 1, 1, stdFile)), 1); + QCOMPARE(c, 'a'); + QCOMPARE(int(ftell(stdFile)), 1); + + { + QFile file; + QVERIFY(file.open(stdFile, QFile::ReadOnly)); + QCOMPARE(file.pos(), qlonglong(1)); + QCOMPARE(file.read(&c, 1), qlonglong(1)); + QCOMPARE(c, 'b'); + QCOMPARE(file.pos(), qlonglong(2)); + } + + fclose(stdFile); +} + +void tst_QFile::isSequential() +{ +#if defined (Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QSKIP("Unix only test.", SkipAll); +#endif + + QFile zero("/dev/null"); + QVERIFY(zero.open(QFile::ReadOnly)); + QVERIFY(zero.isSequential()); +} + +void tst_QFile::encodeName() +{ + QCOMPARE(QFile::encodeName(QString::null), QByteArray()); +} + +void tst_QFile::truncate() +{ + for (int i = 0; i < 2; ++i) { + QFile file("truncate.txt"); + QVERIFY(file.open(QFile::WriteOnly)); + file.write(QByteArray(200, '@')); + file.close(); + + QVERIFY(file.open((i ? QFile::WriteOnly : QFile::ReadWrite) | QFile::Truncate)); + file.write(QByteArray(100, '$')); + file.close(); + + QVERIFY(file.open(QFile::ReadOnly)); + QCOMPARE(file.readAll(), QByteArray(100, '$')); + } +} + +void tst_QFile::seekToPos() +{ + { + QFile file("seekToPos.txt"); + QVERIFY(file.open(QFile::WriteOnly)); + file.write("a\r\nb\r\nc\r\n"); + file.flush(); + } + + QFile file("seekToPos.txt"); + QVERIFY(file.open(QFile::ReadOnly | QFile::Text)); + file.seek(1); + char c; + QVERIFY(file.getChar(&c)); + QCOMPARE(c, '\n'); + + QCOMPARE(file.pos(), qint64(3)); + file.seek(file.pos()); + QCOMPARE(file.pos(), qint64(3)); + + file.seek(1); + file.seek(file.pos()); + QCOMPARE(file.pos(), qint64(1)); + +} + +void tst_QFile::seekAfterEndOfFile() +{ + QLatin1String filename("seekAfterEof.dat"); + QFile::remove(filename); + { + QFile file(filename); + QVERIFY(file.open(QFile::WriteOnly)); + file.write("abcd"); + QCOMPARE(file.size(), qint64(4)); + file.seek(8); + file.write("ijkl"); + QCOMPARE(file.size(), qint64(12)); + file.seek(4); + file.write("efgh"); + QCOMPARE(file.size(), qint64(12)); + file.seek(16); + file.write("----"); + QCOMPARE(file.size(), qint64(20)); + file.flush(); + } + + QFile file(filename); + QVERIFY(file.open(QFile::ReadOnly)); + QByteArray contents = file.readAll(); + QCOMPARE(contents.left(12), QByteArray("abcdefghijkl", 12)); + //bytes 12-15 are uninitialised so we don't care what they read as. + QCOMPARE(contents.mid(16), QByteArray("----", 4)); + file.close(); + QFile::remove(filename); +} + +void tst_QFile::FILEReadWrite() +{ + // Tests modifying a file. First creates it then reads in 4 bytes and then overwrites these + // 4 bytes with new values. At the end check to see the file contains the new values. + + QFile::remove("FILEReadWrite.txt"); + + // create test file + { + QFile f("FILEReadWrite.txt"); + QVERIFY(f.open(QFile::WriteOnly)); + QDataStream ds(&f); + qint8 c = 0; + ds << c; + c = 1; + ds << c; + c = 2; + ds << c; + c = 3; + ds << c; + c = 4; + ds << c; + c = 5; + ds << c; + c = 6; + ds << c; + c = 7; + ds << c; + c = 8; + ds << c; + c = 9; + ds << c; + c = 10; + ds << c; + c = 11; + ds << c; + f.close(); + } + +#ifdef Q_OS_WINCE + FILE *fp = fopen(qPrintable(QCoreApplication::applicationDirPath() + "\\FILEReadWrite.txt"), "r+b"); +#else + FILE *fp = fopen("FILEReadWrite.txt", "r+b"); +#endif + QVERIFY(fp); + QFile file; + QVERIFY(file.open(fp, QFile::ReadWrite)); + QDataStream sfile(&file) ; + + qint8 var1,var2,var3,var4; + while (!sfile.atEnd()) + { + qint64 base = file.pos(); + + QCOMPARE(file.pos(), base + 0); + sfile >> var1; + QCOMPARE(file.pos(), base + 1); + file.flush(); // flushing should not change the base + QCOMPARE(file.pos(), base + 1); + sfile >> var2; + QCOMPARE(file.pos(), base + 2); + sfile >> var3; + QCOMPARE(file.pos(), base + 3); + sfile >> var4; + QCOMPARE(file.pos(), base + 4); + file.seek(file.pos() - 4) ; // Move it back 4, for we are going to write new values based on old ones + QCOMPARE(file.pos(), base + 0); + sfile << qint8(var1 + 5); + QCOMPARE(file.pos(), base + 1); + sfile << qint8(var2 + 5); + QCOMPARE(file.pos(), base + 2); + sfile << qint8(var3 + 5); + QCOMPARE(file.pos(), base + 3); + sfile << qint8(var4 + 5); + QCOMPARE(file.pos(), base + 4); + + } + file.close(); + fclose(fp); + + // check modified file + { + QFile f("FILEReadWrite.txt"); + QVERIFY(f.open(QFile::ReadOnly)); + QDataStream ds(&f); + qint8 c = 0; + ds >> c; + QCOMPARE(c, (qint8)5); + ds >> c; + QCOMPARE(c, (qint8)6); + ds >> c; + QCOMPARE(c, (qint8)7); + ds >> c; + QCOMPARE(c, (qint8)8); + ds >> c; + QCOMPARE(c, (qint8)9); + ds >> c; + QCOMPARE(c, (qint8)10); + ds >> c; + QCOMPARE(c, (qint8)11); + ds >> c; + QCOMPARE(c, (qint8)12); + ds >> c; + QCOMPARE(c, (qint8)13); + ds >> c; + QCOMPARE(c, (qint8)14); + ds >> c; + QCOMPARE(c, (qint8)15); + ds >> c; + QCOMPARE(c, (qint8)16); + f.close(); + } + + QFile::remove("FILEReadWrite.txt"); +} + + +/* +#include <qglobal.h> +#define BUFFSIZE 1 +#define FILESIZE 0x10000000f +void tst_QFile::largeFileSupport() +{ +#ifdef Q_OS_SOLARIS + QSKIP("Solaris does not support statfs", SkipAll); +#else + qlonglong sizeNeeded = 2147483647; + sizeNeeded *= 2; + sizeNeeded += 1024; + qlonglong freespace = qlonglong(0); +#ifdef Q_WS_WIN + _ULARGE_INTEGER free; + if (::GetDiskFreeSpaceEx((wchar_t*)QDir::currentPath().utf16(), &free, 0, 0)) + freespace = free.QuadPart; + if (freespace != 0) { +#elif defined(Q_OS_IRIX) + struct statfs info; + if (statfs(QDir::currentPath().local8Bit(), &info, sizeof(struct statfs), 0) == 0) { + freespace = qlonglong(info.f_bfree * info.f_bsize); +#else + struct statfs info; + if (statfs(const_cast<char *>(QDir::currentPath().toLocal8Bit().constData()), &info) == 0) { + freespace = qlonglong(info.f_bavail * info.f_bsize); +#endif + if (freespace > sizeNeeded) { + QFile bigFile("bigfile"); + if (bigFile.open(QFile::ReadWrite)) { + char c[BUFFSIZE] = {'a'}; + QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE); + qlonglong oldPos = bigFile.pos(); + QVERIFY(bigFile.resize(sizeNeeded)); + QCOMPARE(oldPos, bigFile.pos()); + QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE)); + QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE); + + bigFile.close(); + if (bigFile.open(QFile::ReadOnly)) { + QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE); + int i = 0; + for (i=0; i<BUFFSIZE; i++) + QCOMPARE(c[i], 'a'); + QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE)); + QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE); + for (i=0; i<BUFFSIZE; i++) + QCOMPARE(c[i], 'a'); + bigFile.close(); + QVERIFY(bigFile.remove()); + } else { + QVERIFY(bigFile.remove()); + QFAIL("Could not reopen file"); + } + } else { + QFAIL("Could not open file"); + } + } else { + QSKIP("Not enough space to run test", SkipSingle); + } + } else { + QFAIL("Could not determin disk space"); + } +#endif +} +*/ + +void tst_QFile::i18nFileName_data() +{ + QTest::addColumn<QString>("fileName"); + + QTest::newRow( "01" ) << QString::fromUtf8("xxxxxxx.txt"); +} + +void tst_QFile::i18nFileName() +{ + QFETCH(QString, fileName); + if (QFile::exists(fileName)) { + QVERIFY(QFile::remove(fileName)); + } + { + QFile file(fileName); + QVERIFY(file.open(QFile::WriteOnly | QFile::Text)); + QTextStream ts(&file); + ts.setCodec("UTF-8"); + ts << fileName << endl; + } + { + QFile file(fileName); + QVERIFY(file.open(QFile::ReadOnly | QFile::Text)); + QTextStream ts(&file); + ts.setCodec("UTF-8"); + QString line = ts.readLine(); + QCOMPARE(line, fileName); + } + QVERIFY(QFile::remove(fileName)); +} + + +void tst_QFile::longFileName_data() +{ + QTest::addColumn<QString>("fileName"); + + QTest::newRow( "16 chars" ) << QString::fromLatin1("longFileName.txt"); + QTest::newRow( "52 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName.txt"); + QTest::newRow( "148 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName.txt"); + QTest::newRow( "244 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName.txt"); + QTest::newRow( "244 chars to absolutepath" ) << QFileInfo(QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName.txt")).absoluteFilePath(); + /* needs to be put on a windows 2000 > test machine + QTest::newRow( "244 chars on UNC" ) << QString::fromLatin1("//arsia/D/troll/tmp/longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName.txt");*/ +} + +void tst_QFile::longFileName() +{ + QFETCH(QString, fileName); + if (QFile::exists(fileName)) { + QVERIFY(QFile::remove(fileName)); + } + { + QFile file(fileName); +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QEXPECT_FAIL("244 chars", "Full pathname must be less than 260 chars", Abort); + QEXPECT_FAIL("244 chars to absolutepath", "Full pathname must be less than 260 chars", Abort); +#endif + QVERIFY(file.open(QFile::WriteOnly | QFile::Text)); + QTextStream ts(&file); + ts << fileName << endl; + } + { + QFile file(fileName); + QVERIFY(file.open(QFile::ReadOnly | QFile::Text)); + QTextStream ts(&file); + QString line = ts.readLine(); + QCOMPARE(line, fileName); + } + QString newName = fileName + QLatin1String("1"); + { + QVERIFY(QFile::copy(fileName, newName)); + QFile file(newName); + QVERIFY(file.open(QFile::ReadOnly | QFile::Text)); + QTextStream ts(&file); + QString line = ts.readLine(); + QCOMPARE(line, fileName); + + } + QVERIFY(QFile::remove(newName)); + { + QVERIFY(QFile::rename(fileName, newName)); + QFile file(newName); + QVERIFY(file.open(QFile::ReadOnly | QFile::Text)); + QTextStream ts(&file); + QString line = ts.readLine(); + QCOMPARE(line, fileName); + } + QVERIFY(QFile::exists(newName)); + QVERIFY(QFile::remove(newName)); +} + +class MyEngine : public QAbstractFileEngine +{ +public: + MyEngine(int n) { number = n; } + virtual ~MyEngine() {} + + void setFileName(const QString &) {} + bool open(int ) { return false; } + bool close() { return false; } + bool flush() { return false; } + qint64 size() const { return 123 + number; } + qint64 at() const { return -1; } + bool seek(qint64) { return false; } + bool isSequential() const { return false; } + qint64 read(char *, qint64) { return -1; } + qint64 write(const char *, qint64) { return -1; } + bool remove() { return false; } + bool copy(const QString &) { return false; } + bool rename(const QString &) { return false; } + bool link(const QString &) { return false; } + bool mkdir(const QString &, bool) const { return false; } + bool rmdir(const QString &, bool) const { return false; } + bool setSize(qint64) { return false; } + QStringList entryList(QDir::Filters, const QStringList &) const { return QStringList(); } + bool caseSensitive() const { return false; } + bool isRelativePath() const { return false; } + FileFlags fileFlags(FileFlags) const { return 0; } + bool chmod(uint) { return false; } + QString fileName(FileName) const { return name; } + uint ownerId(FileOwner) const { return 0; } + QString owner(FileOwner) const { return QString(); } + QDateTime fileTime(FileTime) const { return QDateTime(); } + +private: + int number; + QString name; +}; + +class MyHandler : public QAbstractFileEngineHandler +{ +public: + inline QAbstractFileEngine *create(const QString &) const + { + return new MyEngine(1); + } +}; + +class MyHandler2 : public QAbstractFileEngineHandler +{ +public: + inline QAbstractFileEngine *create(const QString &) const + { + return new MyEngine(2); + } +}; + +void tst_QFile::fileEngineHandler() +{ + // A file that does not exist has a size of 0. + QFile::remove("ole.bull"); + QFile file("ole.bull"); + QCOMPARE(file.size(), qint64(0)); + + // Instantiating our handler will enable the new engine. + MyHandler handler; + file.setFileName("ole.bull"); + QCOMPARE(file.size(), qint64(124)); + + // A new, identical handler should take preference over the last one. + MyHandler2 handler2; + file.setFileName("ole.bull"); + QCOMPARE(file.size(), qint64(125)); + +} + +class MyRecursiveHandler : public QAbstractFileEngineHandler +{ +public: + inline QAbstractFileEngine *create(const QString &fileName) const + { + if (fileName.startsWith(":!")) { + QDir dir; + QString realFile = SRCDIR + fileName.mid(2); + if (dir.exists(realFile)) + return new QFSFileEngine(realFile); + } + return 0; + } +}; + +void tst_QFile::useQFileInAFileHandler() +{ + // This test should not dead-lock + MyRecursiveHandler handler; + QFile file(":!tst_qfile.cpp"); + QVERIFY(file.exists()); +} + +void tst_QFile::getCharFF() +{ + QFile file("file.txt"); + file.open(QFile::ReadWrite); + file.write("\xff\xff\xff"); + file.flush(); + file.seek(0); + + char c; + QVERIFY(file.getChar(&c)); + QVERIFY(file.getChar(&c)); + QVERIFY(file.getChar(&c)); +} + +void tst_QFile::remove_and_exists() +{ + QFile::remove("tull_i_grunn.txt"); + QFile f("tull_i_grunn.txt"); + + QVERIFY(!f.exists()); + + bool opened = f.open(QIODevice::WriteOnly); + QVERIFY(opened); + + f.write(QString("testing that remove/exists work...").toLatin1()); + f.close(); + + QVERIFY(f.exists()); + + f.remove(); + QVERIFY(!f.exists()); +} + +void tst_QFile::removeOpenFile() +{ + { + // remove an opened, write-only file + QFile::remove("remove_unclosed.txt"); + QFile f("remove_unclosed.txt"); + + QVERIFY(!f.exists()); + bool opened = f.open(QIODevice::WriteOnly); + QVERIFY(opened); + f.write(QString("testing that remove closes the file first...").toLatin1()); + + bool removed = f.remove(); // remove should both close and remove the file + QVERIFY(removed); + QVERIFY(!f.isOpen()); + QVERIFY(!f.exists()); + QVERIFY(f.error() == QFile::NoError); + } + + { + // remove an opened, read-only file + QFile::remove("remove_unclosed.txt"); + + // first, write a file that we can remove + { + QFile f("remove_unclosed.txt"); + QVERIFY(!f.exists()); + bool opened = f.open(QIODevice::WriteOnly); + QVERIFY(opened); + f.write(QString("testing that remove closes the file first...").toLatin1()); + f.close(); + } + + QFile f("remove_unclosed.txt"); + bool opened = f.open(QIODevice::ReadOnly); + QVERIFY(opened); + f.readAll(); + // this used to only fail on FreeBSD (and Mac OS X) + QVERIFY(f.flush()); + bool removed = f.remove(); // remove should both close and remove the file + QVERIFY(removed); + QVERIFY(!f.isOpen()); + QVERIFY(!f.exists()); + QVERIFY(f.error() == QFile::NoError); + } +} + +void tst_QFile::fullDisk() +{ + QFile file("/dev/full"); + if (!file.exists()) + QSKIP("/dev/full doesn't exist on this system", SkipAll); + + QVERIFY(file.open(QIODevice::WriteOnly)); + file.write("foobar", 6); + + QVERIFY(!file.flush()); + QCOMPARE(file.error(), QFile::ResourceError); + QVERIFY(!file.flush()); + QCOMPARE(file.error(), QFile::ResourceError); + + char c = 0; + file.write(&c, 0); + QVERIFY(!file.flush()); + QCOMPARE(file.error(), QFile::ResourceError); + QCOMPARE(file.write(&c, 1), qint64(1)); + QVERIFY(!file.flush()); + QCOMPARE(file.error(), QFile::ResourceError); + + file.close(); + QVERIFY(!file.isOpen()); + QCOMPARE(file.error(), QFile::ResourceError); + + file.open(QIODevice::WriteOnly); + QCOMPARE(file.error(), QFile::NoError); + QVERIFY(file.flush()); // Shouldn't inherit write buffer + file.close(); + QCOMPARE(file.error(), QFile::NoError); + + // try again without flush: + QVERIFY(file.open(QIODevice::WriteOnly)); + file.write("foobar", 6); + file.close(); + QVERIFY(file.error() != QFile::NoError); +} + +void tst_QFile::writeLargeDataBlock_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("type"); + + QTest::newRow("localfile-QFile") << "./largeblockfile.txt" << (int)OpenQFile; + QTest::newRow("localfile-Fd") << "./largeblockfile.txt" << (int)OpenFd; + QTest::newRow("localfile-Stream") << "./largeblockfile.txt" << (int)OpenStream; +#ifdef Q_OS_SYMBIAN + QTest::newRow("localfile-RFile") << "./largeblockfile.txt" << (int)OpenRFile; +#endif + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + // Some semi-randomness to avoid collisions. + QTest::newRow("unc file") + << QString("//" + QtNetworkSettings::winServerName() + "/TESTSHAREWRITABLE/largefile-%1-%2.txt") + .arg(QHostInfo::localHostName()) + .arg(QTime::currentTime().msec()) << (int)OpenQFile; +#endif +} + +static QByteArray getLargeDataBlock() +{ + static QByteArray array; + + if (array.isNull()) + { +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + int resizeSize = 1024 * 1024; // WinCE and Symbian do not have much space +#else + int resizeSize = 64 * 1024 * 1024; +#endif + array.resize(resizeSize); + for (int i = 0; i < array.size(); ++i) + array[i] = uchar(i); + } + + return array; +} + +void tst_QFile::writeLargeDataBlock() +{ + QFETCH(QString, fileName); + QFETCH( int, type ); + + QByteArray const originalData = getLargeDataBlock(); + + { + QFile file(fileName); + + QVERIFY2( openFile(file, QIODevice::WriteOnly, (FileType)type), + qPrintable(QString("Couldn't open file for writing: [%1]").arg(fileName)) ); + QCOMPARE( file.write(originalData), (qint64)originalData.size() ); + QVERIFY( file.flush() ); + + closeFile(file); + } + + QByteArray readData; + + { + QFile file(fileName); + + QVERIFY2( openFile(file, QIODevice::ReadOnly, (FileType)type), + qPrintable(QString("Couldn't open file for reading: [%1]").arg(fileName)) ); + readData = file.readAll(); + closeFile(file); + } + + QCOMPARE( readData, originalData ); + QVERIFY( QFile::remove(fileName) ); +} + +void tst_QFile::readFromWriteOnlyFile() +{ + QFile file("writeonlyfile"); + QVERIFY(file.open(QFile::WriteOnly)); + char c; + QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device"); + QCOMPARE(file.read(&c, 1), qint64(-1)); +} + +void tst_QFile::writeToReadOnlyFile() +{ + QFile file("readonlyfile"); + QVERIFY(file.open(QFile::ReadOnly)); + char c = 0; + QTest::ignoreMessage(QtWarningMsg, "QIODevice::write: ReadOnly device"); + QCOMPARE(file.write(&c, 1), qint64(-1)); +} + +void tst_QFile::virtualFile() +{ + // test if QFile works with virtual files + QString fname; +#if defined(Q_OS_LINUX) + fname = "/proc/self/maps"; +#elif defined(Q_OS_AIX) + fname = QString("/proc/%1/map").arg(getpid()); +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + fname = "/proc/curproc/map"; +#else + QSKIP("This platform does not have 0-sized virtual files", SkipAll); +#endif + + // consistency check + QFileInfo fi(fname); + QVERIFY(fi.exists()); + QVERIFY(fi.isFile()); + QCOMPARE(fi.size(), Q_INT64_C(0)); + + // open the file + QFile f(fname); + QVERIFY(f.open(QIODevice::ReadOnly)); + QCOMPARE(f.size(), Q_INT64_C(0)); + QVERIFY(f.atEnd()); + + // read data + QByteArray data = f.read(16); + QCOMPARE(data.size(), 16); + QCOMPARE(f.pos(), Q_INT64_C(16)); + + // line-reading + data = f.readLine(); + QVERIFY(!data.isEmpty()); + + // read all: + data = f.readAll(); + QVERIFY(f.pos() != 0); + QVERIFY(!data.isEmpty()); + + // seeking + QVERIFY(f.seek(1)); + QCOMPARE(f.pos(), Q_INT64_C(1)); +} + +void tst_QFile::textFile() +{ +#if defined(Q_OS_WINCE) + FILE *fs = ::fopen((QCoreApplication::applicationDirPath() + "/writeabletextfile").toAscii() , "wt"); +#elif defined(Q_OS_WIN) + FILE *fs = ::fopen("writeabletextfile", "wt"); +#else + FILE *fs = ::fopen("writeabletextfile", "w"); +#endif + QFile f; + QByteArray part1("This\nis\na\nfile\nwith\nnewlines\n"); + QByteArray part2("Add\nsome\nmore\nnewlines\n"); + + QVERIFY(f.open(fs, QIODevice::WriteOnly)); + f.write(part1); + f.write(part2); + f.close(); + ::fclose(fs); + + QFile file("writeabletextfile"); + QVERIFY(file.open(QIODevice::ReadOnly)); + + QByteArray data = file.readAll(); + + QByteArray expected = part1 + part2; +#ifdef Q_OS_WIN + expected.replace("\n", "\015\012"); +#endif + QCOMPARE(data, expected); + file.close(); + file.remove(); +} + +void tst_QFile::rename_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<QString>("destination"); + QTest::addColumn<bool>("result"); + + QTest::newRow("a -> b") << QString("a") << QString("b") << false; + QTest::newRow("a -> .") << QString("a") << QString(".") << false; + QTest::newRow("renamefile -> renamefile") << QString("renamefile") << QString("renamefile") << false; + QTest::newRow("renamefile -> noreadfile") << QString("renamefile") << QString("noreadfile") << false; +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + QTest::newRow("renamefile -> /etc/renamefile") << QString("renamefile") << QString("/etc/renamefile") << false; +#endif + QTest::newRow("renamefile -> renamedfile") << QString("renamefile") << QString("renamedfile") << true; + QTest::newRow("renamefile -> ..") << QString("renamefile") << QString("..") << false; +} + +void tst_QFile::rename() +{ + QFETCH(QString, source); + QFETCH(QString, destination); + QFETCH(bool, result); + + QFile::remove("renamedfile"); + QFile f("renamefile"); + f.open(QFile::WriteOnly); + f.close(); + + QFile file(source); + QCOMPARE(file.rename(destination), result); + + if (result) + QCOMPARE(file.error(), QFile::NoError); + else + QCOMPARE(file.error(), QFile::RenameError); + + QFile::remove("renamefile"); +} + +/*! + \since 4.5 + + Some special files have QFile::atEnd() returning true, even though there is + more data available. True for corner cases, as well as some mounts on OS X. + + Here, we reproduce that condition by having a QFile sub-class with this + peculiar atEnd() behavior. + + See task 231583. + */ +void tst_QFile::renameWithAtEndSpecialFile() const +{ + class PeculiarAtEnd : public QFile + { + public: + virtual bool atEnd() const + { + return true; + } + }; + + const QString newName(QLatin1String("newName.txt")); + /* Cleanup, so we're a bit more robust. */ + QFile::remove(newName); + + const QString originalName(QString(SRCDIR "forRenaming.txt")); + + PeculiarAtEnd file; + file.setFileName(originalName); + QVERIFY(file.open(QIODevice::ReadOnly)); + + QVERIFY(file.rename(newName)); + + file.close(); + /* Guess what, we have to rename it back, otherwise we'll fail on second + * invocation. */ + QVERIFY(QFile::rename(newName, originalName)); +} + +void tst_QFile::renameFallback() +{ + // Using a resource file both to trigger QFile::rename's fallback handling + // and as a *read-only* source whose move should fail. + QFile file(":/rename-fallback.qrc"); + QVERIFY(file.exists() && "(test-precondition)"); + QFile::remove("file-rename-destination.txt"); + + QVERIFY(!file.rename("file-rename-destination.txt")); + QVERIFY(!QFile::exists("file-rename-destination.txt")); + QVERIFY(!file.isOpen()); +} + +void tst_QFile::renameMultiple() +{ + // create the file if it doesn't exist + QFile file("file-to-be-renamed.txt"); + QFile file2("existing-file.txt"); + QVERIFY(file.open(QIODevice::ReadWrite) && "(test-precondition)"); + QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)"); + + // any stale files from previous test failures? + QFile::remove("file-renamed-once.txt"); + QFile::remove("file-renamed-twice.txt"); + + // begin testing + QVERIFY(QFile::exists("existing-file.txt")); + QVERIFY(!file.rename("existing-file.txt")); + QCOMPARE(file.error(), QFile::RenameError); + QCOMPARE(file.fileName(), QString("file-to-be-renamed.txt")); + + QVERIFY(file.rename("file-renamed-once.txt")); + QVERIFY(!file.isOpen()); + QCOMPARE(file.fileName(), QString("file-renamed-once.txt")); + + QVERIFY(QFile::exists("existing-file.txt")); + QVERIFY(!file.rename("existing-file.txt")); + QCOMPARE(file.error(), QFile::RenameError); + QCOMPARE(file.fileName(), QString("file-renamed-once.txt")); + + QVERIFY(file.rename("file-renamed-twice.txt")); + QVERIFY(!file.isOpen()); + QCOMPARE(file.fileName(), QString("file-renamed-twice.txt")); + + QVERIFY(QFile::exists("existing-file.txt")); + QVERIFY(!QFile::exists("file-to-be-renamed.txt")); + QVERIFY(!QFile::exists("file-renamed-once.txt")); + QVERIFY(QFile::exists("file-renamed-twice.txt")); + + file.remove(); + file2.remove(); + QVERIFY(!QFile::exists("file-renamed-twice.txt")); + QVERIFY(!QFile::exists("existing-file.txt")); +} + +void tst_QFile::appendAndRead() +{ + QFile writeFile(QLatin1String("appendfile.txt")); + QVERIFY(writeFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); + + QFile readFile(QLatin1String("appendfile.txt")); + QVERIFY(readFile.open(QIODevice::ReadOnly)); + + // Write to the end of the file, then read that character back, and so on. + for (int i = 0; i < 100; ++i) { + char c = '\0'; + writeFile.putChar(char(i % 256)); + writeFile.flush(); + QVERIFY(readFile.getChar(&c)); + QCOMPARE(c, char(i % 256)); + QCOMPARE(readFile.pos(), writeFile.pos()); + } + + // Write blocks and read them back + for (int j = 0; j < 18; ++j) { + writeFile.write(QByteArray(1 << j, '@')); + writeFile.flush(); + QCOMPARE(readFile.read(1 << j).size(), 1 << j); + } + + readFile.close(); + QFile::remove(QLatin1String("appendfile.txt")); +} + +void tst_QFile::miscWithUncPathAsCurrentDir() +{ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QString current = QDir::currentPath(); + QVERIFY(QDir::setCurrent("//" + QtNetworkSettings::winServerName() + "/testshare")); + QFile file("test.pri"); + QVERIFY(file.exists()); + QCOMPARE(int(file.size()), 34); + QVERIFY(file.open(QIODevice::ReadOnly)); + QVERIFY(QDir::setCurrent(current)); +#endif +} + +void tst_QFile::standarderror() +{ + QFile f; + bool ok = f.open(stderr, QFile::WriteOnly); + QVERIFY(ok); + f.close(); +} + +void tst_QFile::handle() +{ + int fd; +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QFile file(SRCDIR "tst_qfile.cpp"); + QVERIFY(file.open(QIODevice::ReadOnly)); + fd = int(file.handle()); + QVERIFY(fd > 2); + QCOMPARE(int(file.handle()), fd); + char c = '\0'; + QT_READ(int(file.handle()), &c, 1); + QCOMPARE(c, '/'); + + // test if the QFile and the handle remain in sync + QVERIFY(file.getChar(&c)); + QCOMPARE(c, '*'); + + // same, but read from QFile first now + file.close(); + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)); + fd = int(file.handle()); + QVERIFY(fd > 2); + QVERIFY(file.getChar(&c)); + QCOMPARE(c, '/'); +#ifdef Q_OS_UNIX + QCOMPARE(QT_READ(fd, &c, 1), ssize_t(1)); +#else + QCOMPARE(QT_READ(fd, &c, 1), 1); +#endif + + QCOMPARE(c, '*'); +#endif + + //test round trip of adopted stdio file handle + QFile file2; + FILE *fp = fopen(SRCDIR "tst_qfile.cpp", "r"); + file2.open(fp, QIODevice::ReadOnly); + QCOMPARE(int(file2.handle()), int(fileno(fp))); + QCOMPARE(int(file2.handle()), int(fileno(fp))); + fclose(fp); + + //test round trip of adopted posix file handle +#ifdef Q_OS_UNIX + QFile file3; + fd = QT_OPEN(SRCDIR "tst_qfile.cpp", QT_OPEN_RDONLY); + file3.open(fd, QIODevice::ReadOnly); + QCOMPARE(int(file3.handle()), fd); + QT_CLOSE(fd); +#endif +} + +void tst_QFile::nativeHandleLeaks() +{ +#ifdef Q_OS_SYMBIAN + QSKIP("test assumptions invalid for symbian", SkipAll); +#else + int fd1, fd2; + +#ifdef Q_OS_WIN + HANDLE handle1, handle2; +#endif + + { + QFile file("qt_file.tmp"); + QVERIFY( file.open(QIODevice::ReadWrite) ); + + fd1 = file.handle(); + QVERIFY( -1 != fd1 ); + } + +#ifdef Q_OS_WIN + handle1 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + QVERIFY( INVALID_HANDLE_VALUE != handle1 ); + QVERIFY( ::CloseHandle(handle1) ); +#endif + + { + QFile file("qt_file.tmp"); + QVERIFY( file.open(QIODevice::ReadOnly) ); + + fd2 = file.handle(); + QVERIFY( -1 != fd2 ); + } + +#ifdef Q_OS_WIN + handle2 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + QVERIFY( INVALID_HANDLE_VALUE != handle2 ); + QVERIFY( ::CloseHandle(handle2) ); +#endif + + QCOMPARE( fd2, fd1 ); + +#ifdef Q_OS_WIN + QCOMPARE( handle2, handle1 ); +#endif +#endif +} + +void tst_QFile::readEof_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<int>("imode"); + + QTest::newRow("buffered") << SRCDIR "testfile.txt" << 0; + QTest::newRow("unbuffered") << SRCDIR "testfile.txt" << int(QIODevice::Unbuffered); + +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + QTest::newRow("sequential,buffered") << "/dev/null" << 0; + QTest::newRow("sequential,unbuffered") << "/dev/null" << int(QIODevice::Unbuffered); +#endif +} + +void tst_QFile::readEof() +{ + QFETCH(QString, filename); + QFETCH(int, imode); + QIODevice::OpenMode mode = QIODevice::OpenMode(imode); + + { + QFile file(filename); + QVERIFY(file.open(QIODevice::ReadOnly | mode)); + bool isSequential = file.isSequential(); + if (!isSequential) { + QVERIFY(file.seek(245)); + QVERIFY(file.atEnd()); + } + + char buf[10]; + int ret = file.read(buf, sizeof buf); + QCOMPARE(ret, 0); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + + // Do it again to ensure that we get the same result + ret = file.read(buf, sizeof buf); + QCOMPARE(ret, 0); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + } + + { + QFile file(filename); + QVERIFY(file.open(QIODevice::ReadOnly | mode)); + bool isSequential = file.isSequential(); + if (!isSequential) { + QVERIFY(file.seek(245)); + QVERIFY(file.atEnd()); + } + + QByteArray ret = file.read(10); + QVERIFY(ret.isEmpty()); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + + // Do it again to ensure that we get the same result + ret = file.read(10); + QVERIFY(ret.isEmpty()); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + } + + { + QFile file(filename); + QVERIFY(file.open(QIODevice::ReadOnly | mode)); + bool isSequential = file.isSequential(); + if (!isSequential) { + QVERIFY(file.seek(245)); + QVERIFY(file.atEnd()); + } + + char buf[10]; + int ret = file.readLine(buf, sizeof buf); + QCOMPARE(ret, -1); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + + // Do it again to ensure that we get the same result + ret = file.readLine(buf, sizeof buf); + QCOMPARE(ret, -1); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + } + + { + QFile file(filename); + QVERIFY(file.open(QIODevice::ReadOnly | mode)); + bool isSequential = file.isSequential(); + if (!isSequential) { + QVERIFY(file.seek(245)); + QVERIFY(file.atEnd()); + } + + QByteArray ret = file.readLine(); + QVERIFY(ret.isNull()); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + + // Do it again to ensure that we get the same result + ret = file.readLine(); + QVERIFY(ret.isNull()); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + } + + { + QFile file(filename); + QVERIFY(file.open(QIODevice::ReadOnly | mode)); + bool isSequential = file.isSequential(); + if (!isSequential) { + QVERIFY(file.seek(245)); + QVERIFY(file.atEnd()); + } + + char c; + QVERIFY(!file.getChar(&c)); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + + // Do it again to ensure that we get the same result + QVERIFY(!file.getChar(&c)); + QVERIFY(file.error() == QFile::NoError); + QVERIFY(file.atEnd()); + } +} + +void tst_QFile::task167217() +{ + // Regression introduced in 4.3.0; after a failed stat, pos() could no + // longer be calculated correctly. + QFile::remove("tmp.txt"); + QFile file("tmp.txt"); + QVERIFY(!file.exists()); + QVERIFY(file.open(QIODevice::Append)); + QVERIFY(file.exists()); + file.write("qt430", 5); + QVERIFY(!file.isSequential()); + QCOMPARE(file.pos(), qint64(5)); + file.remove(); +} + +#define FILESIZE 65536 * 3 + +void tst_QFile::map_data() +{ + QTest::addColumn<int>("fileSize"); + QTest::addColumn<int>("offset"); + QTest::addColumn<int>("size"); + QTest::addColumn<QFile::FileError>("error"); + + QTest::newRow("zero") << FILESIZE << 0 << FILESIZE << QFile::NoError; + QTest::newRow("small, but 0") << FILESIZE << 30 << FILESIZE - 30 << QFile::NoError; + QTest::newRow("a page") << FILESIZE << 4096 << FILESIZE - 4096 << QFile::NoError; + QTest::newRow("+page") << FILESIZE << 5000 << FILESIZE - 5000 << QFile::NoError; + QTest::newRow("++page") << FILESIZE << 65576 << FILESIZE - 65576 << QFile::NoError; + QTest::newRow("bad size") << FILESIZE << 0 << -1 << QFile::ResourceError; + QTest::newRow("bad offset") << FILESIZE << -1 << 1 << QFile::UnspecifiedError; + QTest::newRow("zerozero") << FILESIZE << 0 << 0 << QFile::UnspecifiedError; +} + +void tst_QFile::map() +{ + QFETCH(int, fileSize); + QFETCH(int, offset); + QFETCH(int, size); + QFETCH(QFile::FileError, error); + + QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile"; + +#ifdef Q_WS_WINCE + fileName = QFileInfo(fileName).absoluteFilePath(); +#endif + + if (QFile::exists(fileName)) { + QVERIFY(QFile::setPermissions(fileName, + QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser)); + QFile::remove(fileName); + } + QFile file(fileName); + + // invalid, not open + uchar *memory = file.map(0, size); + QVERIFY(!memory); + QCOMPARE(file.error(), QFile::PermissionsError); + QVERIFY(!file.unmap(memory)); + QCOMPARE(file.error(), QFile::PermissionsError); + + // make a file + QVERIFY(file.open(QFile::ReadWrite)); + QVERIFY(file.resize(fileSize)); + QVERIFY(file.flush()); + file.close(); + QVERIFY(file.open(QFile::ReadWrite)); + memory = file.map(offset, size); + if (error != QFile::NoError) { + + QVERIFY(file.error() != QFile::NoError); + return; + } + + QCOMPARE(file.error(), error); + QVERIFY(memory); + memory[0] = 'Q'; + QVERIFY(file.unmap(memory)); + QCOMPARE(file.error(), QFile::NoError); + + // Verify changes were saved + memory = file.map(offset, size); + QCOMPARE(file.error(), QFile::NoError); + QVERIFY(memory); + QVERIFY(memory[0] == 'Q'); + QVERIFY(file.unmap(memory)); + QCOMPARE(file.error(), QFile::NoError); + + // hpux wont let you map multiple times. +#if !defined(Q_OS_HPUX) && !defined(Q_USE_DEPRECATED_MAP_API) && !defined(Q_OS_WINCE) + // exotic test to make sure that multiple maps work + + // note: windows ce does not reference count mutliple maps + // it's essentially just the same reference but it + // cause a resource lock on the file which prevents it + // from being removed uchar *memory1 = file.map(0, file.size()); + uchar *memory1 = file.map(0, file.size()); + QCOMPARE(file.error(), QFile::NoError); + uchar *memory2 = file.map(0, file.size()); + QCOMPARE(file.error(), QFile::NoError); + QVERIFY(memory1); + QVERIFY(memory2); + QVERIFY(file.unmap(memory1)); + QCOMPARE(file.error(), QFile::NoError); + QVERIFY(file.unmap(memory2)); + QCOMPARE(file.error(), QFile::NoError); + memory1 = file.map(0, file.size()); + QCOMPARE(file.error(), QFile::NoError); + QVERIFY(memory1); + QVERIFY(file.unmap(memory1)); + QCOMPARE(file.error(), QFile::NoError); +#endif + + file.close(); + +#if defined(Q_OS_SYMBIAN) + if (false) // No permissions for user makes no sense in Symbian +#elif defined(Q_OS_UNIX) + if (::getuid() != 0) + // root always has permissions +#endif + { + // Change permissions on a file, just to confirm it would fail + QFile::Permissions originalPermissions = file.permissions(); + QVERIFY(file.setPermissions(QFile::ReadOther)); + QVERIFY(!file.open(QFile::ReadWrite)); + memory = file.map(offset, size); + QCOMPARE(file.error(), QFile::PermissionsError); + QVERIFY(!memory); + QVERIFY(file.setPermissions(originalPermissions)); + } + QVERIFY(file.remove()); +} + +void tst_QFile::mapResource_data() +{ + QTest::addColumn<int>("offset"); + QTest::addColumn<int>("size"); + QTest::addColumn<QFile::FileError>("error"); + QTest::addColumn<QString>("fileName"); + + QString validFile = ":/tst_qfileinfo/resources/file1.ext1"; + QString invalidFile = ":/tst_qfileinfo/resources/filefoo.ext1"; + + for (int i = 0; i < 2; ++i) { + QString file = (i == 0) ? validFile : invalidFile; + QTest::newRow("0, 0") << 0 << 0 << QFile::UnspecifiedError << file; + QTest::newRow("0, BIG") << 0 << 4096 << QFile::UnspecifiedError << file; + QTest::newRow("-1, 0") << -1 << 0 << QFile::UnspecifiedError << file; + QTest::newRow("0, -1") << 0 << -1 << QFile::UnspecifiedError << file; + } + + QTest::newRow("0, 1") << 0 << 1 << QFile::NoError << validFile; +} + +void tst_QFile::mapResource() +{ + QFETCH(QString, fileName); + QFETCH(int, offset); + QFETCH(int, size); + QFETCH(QFile::FileError, error); + + QFile file(fileName); + uchar *memory = file.map(offset, size); + QCOMPARE(file.error(), error); + QVERIFY((error == QFile::NoError) ? (memory != 0) : (memory == 0)); + if (error == QFile::NoError) + QCOMPARE(QString(memory[0]), QString::number(offset + 1)); + QVERIFY(file.unmap(memory)); +} + +void tst_QFile::mapOpenMode_data() +{ + QTest::addColumn<int>("openMode"); + + QTest::newRow("ReadOnly") << int(QIODevice::ReadOnly); + //QTest::newRow("WriteOnly") << int(QIODevice::WriteOnly); // this doesn't make sense + QTest::newRow("ReadWrite") << int(QIODevice::ReadWrite); + QTest::newRow("ReadOnly,Unbuffered") << int(QIODevice::ReadOnly | QIODevice::Unbuffered); + QTest::newRow("ReadWrite,Unbuffered") << int(QIODevice::ReadWrite | QIODevice::Unbuffered); +} + +void tst_QFile::mapOpenMode() +{ + QFETCH(int, openMode); + static const qint64 fileSize = 4096; + + QByteArray pattern(fileSize, 'A'); + + QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile"; + if (QFile::exists(fileName)) { + QVERIFY(QFile::setPermissions(fileName, + QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser)); + QFile::remove(fileName); + } + QFile file(fileName); + + // make a file + QVERIFY(file.open(QFile::ReadWrite)); + QVERIFY(file.write(pattern)); + QVERIFY(file.flush()); + file.close(); + + // open according to our mode + QVERIFY(file.open(QIODevice::OpenMode(openMode))); + + uchar *memory = file.map(0, fileSize); + QVERIFY(memory); + QVERIFY(memcmp(memory, pattern, fileSize) == 0); + + if (openMode & QIODevice::WriteOnly) { + // try to write to the file + *memory = 'a'; + file.unmap(memory); + file.close(); + file.open(QIODevice::OpenMode(openMode)); + file.seek(0); + char c; + QVERIFY(file.getChar(&c)); + QCOMPARE(c, 'a'); + } + + file.close(); +} + +void tst_QFile::openDirectory() +{ + QFile f1(SRCDIR "resources"); + // it's a directory, it must exist + QVERIFY(f1.exists()); + + // ...but not be openable + QVERIFY(!f1.open(QIODevice::ReadOnly)); + f1.close(); + QVERIFY(!f1.open(QIODevice::ReadOnly|QIODevice::Unbuffered)); + f1.close(); + QVERIFY(!f1.open(QIODevice::ReadWrite)); + f1.close(); + QVERIFY(!f1.open(QIODevice::WriteOnly)); + f1.close(); + QVERIFY(!f1.open(QIODevice::WriteOnly|QIODevice::Unbuffered)); + f1.close(); +} + +void tst_QFile::openStandardStreamsFileDescriptors() +{ +#ifdef Q_WS_WINCE + //allthough Windows CE (not mobile!) has functions that allow redirecting + //the standard file descriptors to a file (see SetStdioPathW/GetStdioPathW) + //it does not have functions to simply open them like below . + QSKIP("Opening standard streams on Windows CE via descriptor not implemented", SkipAll); +#endif + // Using file descriptors + { + QFile in; + in.open(STDIN_FILENO, QIODevice::ReadOnly); + QCOMPARE( in.pos(), (qint64)0 ); + QCOMPARE( in.size(), (qint64)0 ); + QVERIFY( in.isSequential() ); + } + + { + QFile out; + out.open(STDOUT_FILENO, QIODevice::WriteOnly); + QCOMPARE( out.pos(), (qint64)0 ); + QCOMPARE( out.size(), (qint64)0 ); + QVERIFY( out.isSequential() ); + } + + { + QFile err; + err.open(STDERR_FILENO, QIODevice::WriteOnly); + QCOMPARE( err.pos(), (qint64)0 ); + QCOMPARE( err.size(), (qint64)0 ); + QVERIFY( err.isSequential() ); + } +} + +void tst_QFile::openStandardStreamsBufferedStreams() +{ +#if defined (Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QSKIP("Unix only test.", SkipAll); +#endif + // Using streams + { + QFile in; + in.open(stdin, QIODevice::ReadOnly); + QCOMPARE( in.pos(), (qint64)0 ); + QCOMPARE( in.size(), (qint64)0 ); + QVERIFY( in.isSequential() ); + } + + { + QFile out; + out.open(stdout, QIODevice::WriteOnly); + QCOMPARE( out.pos(), (qint64)0 ); + QCOMPARE( out.size(), (qint64)0 ); + QVERIFY( out.isSequential() ); + } + + { + QFile err; + err.open(stderr, QIODevice::WriteOnly); + QCOMPARE( err.pos(), (qint64)0 ); + QCOMPARE( err.size(), (qint64)0 ); + QVERIFY( err.isSequential() ); + } +} + +void tst_QFile::openStandardStreams() +{ + openStandardStreamsFileDescriptors(); + openStandardStreamsBufferedStreams(); +} + +void tst_QFile::writeNothing() +{ + for (int i = 0; i < NumberOfFileTypes; ++i) { + QFile file("file.txt"); + QVERIFY( openFile(file, QIODevice::WriteOnly | QIODevice::Unbuffered, FileType(i)) ); + QVERIFY( 0 == file.write((char *)0, 0) ); + QCOMPARE( file.error(), QFile::NoError ); + closeFile(file); + } +} + +void tst_QFile::resize_data() +{ + QTest::addColumn<int>("filetype"); + + QTest::newRow("native") << int(OpenQFile); + QTest::newRow("fileno") << int(OpenFd); + QTest::newRow("stream") << int(OpenStream); +#ifdef Q_OS_SYMBIAN + QTest::newRow("rfile") << int(OpenRFile); +#endif +} + +void tst_QFile::resize() +{ + QFETCH(int, filetype); + QString filename(QLatin1String("file.txt")); + QFile file(filename); + QVERIFY(openFile(file, QIODevice::ReadWrite, FileType(filetype))); + QVERIFY(file.resize(8)); + QCOMPARE(file.size(), qint64(8)); + closeFile(file); + QFile::resize(filename, 4); + QCOMPARE(QFileInfo(filename).size(), qint64(4)); + QVERIFY(QFile::remove(filename)); +} + +void tst_QFile::objectConstructors() +{ + QObject ob; + QFile* file1 = new QFile(SRCDIR "testfile.txt", &ob); + QFile* file2 = new QFile(&ob); + QVERIFY(file1->exists()); + QVERIFY(!file2->exists()); +} + +#ifdef Q_OS_SYMBIAN +void tst_QFile::platformSecurity_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<bool>("readable"); + QTest::addColumn<bool>("writable"); + + QString selfname = QCoreApplication::applicationFilePath(); + QString ownprivate = QCoreApplication::applicationDirPath(); + QString owndrive = selfname.left(2); + bool amiprivileged = RProcess().HasCapability(ECapabilityAllFiles); + QTest::newRow("resource") << owndrive + "/resource/apps/tst_qfile.rsc" << true << amiprivileged; + QTest::newRow("sys") << selfname << amiprivileged << false; + QTest::newRow("own private") << ownprivate + "/testfile.txt" << true << true; + QTest::newRow("other private") << owndrive + "/private/10003a3f/import/apps/tst_qfile_reg.rsc" << amiprivileged << amiprivileged; +} + +void tst_QFile::platformSecurity() +{ + QFETCH(QString,file); + QFETCH(bool,readable); + QFETCH(bool,writable); + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadOnly), readable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadOnly | QIODevice::Unbuffered), readable); + } + + //append mode used to avoid truncating the files. + { + QFile f(file); + QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append), writable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered), writable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadWrite), writable); + } + + { + QFile f(file); + QCOMPARE(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered), writable); + } +} +#endif + +void tst_QFile::caseSensitivity() +{ +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WIN) || defined(Q_OS_MAC) + const bool caseSensitive = false; +#else + const bool caseSensitive = true; +#endif + QByteArray testData("a little test"); + QString filename("File.txt"); + { + QFile f(filename); + QVERIFY(f.open(QIODevice::WriteOnly)); + QVERIFY(f.write(testData)); + f.close(); + } + QStringList alternates; + QFileInfo fi(filename); + QVERIFY(fi.exists()); + alternates << "file.txt" << "File.TXT" << "fIlE.TxT" << fi.absoluteFilePath().toUpper() << fi.absoluteFilePath().toLower(); + foreach (QString alt, alternates) { + QFileInfo fi2(alt); + QCOMPARE(fi2.exists(), !caseSensitive); + QCOMPARE(fi.size() == fi2.size(), !caseSensitive); + QFile f2(alt); + QCOMPARE(f2.open(QIODevice::ReadOnly), !caseSensitive); + if (!caseSensitive) + QCOMPARE(f2.readAll(), testData); + } +} + +//MSVCRT asserts when any function is called with a closed file handle. +//This replaces the default crashing error handler with one that ignores the error (allowing EBADF to be returned) +class AutoIgnoreInvalidParameter +{ +public: +#if defined(Q_OS_WIN) && defined (Q_CC_MSVC) + static void ignore_invalid_parameter(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t) {} + AutoIgnoreInvalidParameter() + { + oldHandler = _set_invalid_parameter_handler(ignore_invalid_parameter); + //also disable the abort/retry/ignore popup + oldReportMode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); + } + ~AutoIgnoreInvalidParameter() + { + //restore previous settings + _set_invalid_parameter_handler(oldHandler); + _CrtSetReportMode(_CRT_ASSERT, oldReportMode); + } + _invalid_parameter_handler oldHandler; + int oldReportMode; +#endif +}; + +void tst_QFile::autocloseHandle() +{ +#ifdef Q_OS_SYMBIAN + // these tests are a bit different, because using a closed file handle results in a panic rather than error + { + QFile file("readonlyfile"); + QFile file2("readonlyfile"); + QVERIFY(openFile(file, QIODevice::ReadOnly, OpenRFile, QFile::AutoCloseHandle)); + // file is opened with mandatory lock, so opening again should fail + QVERIFY(!file2.open(QIODevice::ReadOnly)); + + file.close(); + // opening again should now succeed (because handle is closed) + QVERIFY(file2.open(QIODevice::ReadOnly)); + } + + { + QFile file("readonlyfile"); + QFile file2("readonlyfile"); + QVERIFY(openFile(file, QIODevice::ReadOnly, OpenRFile, QFile::DontCloseHandle)); + // file is opened with mandatory lock, so opening again should fail + QVERIFY(!file2.open(QIODevice::ReadOnly)); + + file.close(); + // opening again should still fail (because handle is not auto closed) + QVERIFY(!file2.open(QIODevice::ReadOnly)); + + rfile_.Close(); + // now it should succeed + QVERIFY(file2.open(QIODevice::ReadOnly)); + } +#endif + + { + QFile file("readonlyfile"); + QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::AutoCloseHandle)); + int fd = fd_; + QCOMPARE(file.handle(), fd); + file.close(); + fd_ = -1; + QCOMPARE(file.handle(), -1); + AutoIgnoreInvalidParameter a; + Q_UNUSED(a); + //file is closed, read should fail + char buf; + QCOMPARE((int)QT_READ(fd, &buf, 1), -1); + QVERIFY(errno = EBADF); + } + + { + QFile file("readonlyfile"); + QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::DontCloseHandle)); + QCOMPARE(file.handle(), fd_); + file.close(); + QCOMPARE(file.handle(), -1); + //file is not closed, read should succeed + char buf; + QCOMPARE((int)QT_READ(fd_, &buf, 1), 1); + ::close(fd_); + fd_ = -1; + } + + { + QFile file("readonlyfile"); + QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::AutoCloseHandle)); + int fd = fileno(stream_); + QCOMPARE(file.handle(), fd); + file.close(); + stream_ = 0; + QCOMPARE(file.handle(), -1); + AutoIgnoreInvalidParameter a; + Q_UNUSED(a); + //file is closed, read should fail + char buf; + QCOMPARE((int)QT_READ(fd, &buf, 1), -1); //not using fread because the FILE* was freed by fclose + } + + { + QFile file("readonlyfile"); + QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::DontCloseHandle)); + QCOMPARE(file.handle(), fileno(stream_)); + file.close(); + QCOMPARE(file.handle(), -1); + //file is not closed, read should succeed + char buf; + QCOMPARE(int(::fread(&buf, 1, 1, stream_)), 1); + ::fclose(stream_); + stream_ = 0; + } +} + +QTEST_MAIN(tst_QFile) +#include "tst_qfile.moc" diff --git a/tests/auto/corelib/io/qfile/two.dots.file b/tests/auto/corelib/io/qfile/two.dots.file new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qfile/two.dots.file @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qfileinfo/.gitignore b/tests/auto/corelib/io/qfileinfo/.gitignore new file mode 100644 index 0000000000..fc1a8906af --- /dev/null +++ b/tests/auto/corelib/io/qfileinfo/.gitignore @@ -0,0 +1 @@ +tst_qfileinfo diff --git a/tests/auto/corelib/io/qfileinfo/qfileinfo.pro b/tests/auto/corelib/io/qfileinfo/qfileinfo.pro new file mode 100644 index 0000000000..2fd626a57e --- /dev/null +++ b/tests/auto/corelib/io/qfileinfo/qfileinfo.pro @@ -0,0 +1,33 @@ +load(qttest_p4) +SOURCES += tst_qfileinfo.cpp + +QT = core-private + + +RESOURCES += qfileinfo.qrc + +wince*:|symbian: { + deploy.files += qfileinfo.qrc tst_qfileinfo.cpp + res.files = resources\\file1 resources\\file1.ext1 resources\\file1.ext1.ext2 + res.path = resources + DEPLOYMENT += deploy res +} + +win32*:LIBS += -ladvapi32 -lnetapi32 + +symbian { + TARGET.CAPABILITY=AllFiles + LIBS *= -lefsrv + INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE # Needed for e32svr.h in S^3 envs + } + +# support for running test from shadow build directory +wince* { + DEFINES += SRCDIR=\\\"\\\" +} else:symbian { + # do not define SRCDIR at all +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qfileinfo/qfileinfo.qrc b/tests/auto/corelib/io/qfileinfo/qfileinfo.qrc new file mode 100644 index 0000000000..2c63d8afeb --- /dev/null +++ b/tests/auto/corelib/io/qfileinfo/qfileinfo.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/tst_qfileinfo/"> + <file>resources/</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qfileinfo/resources/file1 b/tests/auto/corelib/io/qfileinfo/resources/file1 new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qfileinfo/resources/file1 diff --git a/tests/auto/corelib/io/qfileinfo/resources/file1.ext1 b/tests/auto/corelib/io/qfileinfo/resources/file1.ext1 new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qfileinfo/resources/file1.ext1 diff --git a/tests/auto/corelib/io/qfileinfo/resources/file1.ext1.ext2 b/tests/auto/corelib/io/qfileinfo/resources/file1.ext1.ext2 new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qfileinfo/resources/file1.ext1.ext2 diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp new file mode 100644 index 0000000000..c3d106d2fd --- /dev/null +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -0,0 +1,1803 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qfile.h> +#include <qdir.h> +#include <qcoreapplication.h> +#include <qlibrary.h> +#include <qtemporaryfile.h> +#include <qdir.h> +#include <qfileinfo.h> +#ifdef Q_OS_UNIX +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <pwd.h> +#endif +#ifdef Q_OS_WIN +#define _WIN32_WINNT 0x500 +#include <qt_windows.h> +#include <qlibrary.h> +#include <lm.h> +#endif +#include <qplatformdefs.h> +#include <qdebug.h> +#ifdef Q_OS_SYMBIAN +#include <f32file.h> +#include <private/qcore_symbian_p.h> +#endif +#include "../../../network-settings.h" +#include <private/qfileinfo_p.h> +#include "../../../../shared/filesystem.h" + +#if defined(Q_OS_SYMBIAN) +# define SRCDIR "" +# define NO_SYMLINKS +#endif + +QT_BEGIN_NAMESPACE +extern Q_AUTOTEST_EXPORT bool qIsLikelyToBeNfs(int /* handle */); +QT_END_NAMESPACE + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFileInfo : public QObject +{ +Q_OBJECT + +public: + tst_QFileInfo(); + ~tst_QFileInfo(); + +private slots: + void getSetCheck(); + + void copy(); + + void isFile_data(); + void isFile(); + + void isDir_data(); + void isDir(); + + void isRoot_data(); + void isRoot(); + + void exists_data(); + void exists(); + + void absolutePath_data(); + void absolutePath(); + + void absFilePath_data(); + void absFilePath(); + + void canonicalPath(); + void canonicalFilePath(); + + void fileName_data(); + void fileName(); + + void bundleName_data(); + void bundleName(); + + void dir_data(); + void dir(); + + void suffix_data(); + void suffix(); + + void completeSuffix_data(); + void completeSuffix(); + + void baseName_data(); + void baseName(); + + void completeBaseName_data(); + void completeBaseName(); + + void permission_data(); + void permission(); + + void size_data(); + void size(); + + void systemFiles(); + + void compare_data(); + void compare(); + + void consistent_data(); + void consistent(); + + void fileTimes_data(); + void fileTimes(); + void fileTimes_oldFile(); + + void isSymLink_data(); + void isSymLink(); + + void isHidden_data(); + void isHidden(); +#if defined(Q_OS_MAC) + void isHiddenFromFinder(); +#endif + + void isBundle_data(); + void isBundle(); + + void isLocalFs_data(); + void isLocalFs(); + + void refresh(); + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + void ntfsJunctionPointsAndSymlinks_data(); + void ntfsJunctionPointsAndSymlinks(); + void brokenShortcut(); +#endif + + void isWritable(); + void isExecutable(); + void testDecomposedUnicodeNames_data(); + void testDecomposedUnicodeNames(); + + void equalOperator() const; + void equalOperatorWithDifferentSlashes() const; + void notEqualOperator() const; + + void detachingOperations(); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + void owner(); +#endif + void group(); + + void invalidState(); +}; + +tst_QFileInfo::tst_QFileInfo() +{ +} + +tst_QFileInfo::~tst_QFileInfo() +{ + QFile::remove("brokenlink.lnk"); + QFile::remove("link.lnk"); + QFile::remove("file1"); + QFile::remove("dummyfile"); + QFile::remove("simplefile.txt"); + QFile::remove("longFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileName.txt"); +#ifdef Q_OS_SYMBIAN + QFile::remove("hidden.txt"); + QFile::remove("nothidden.txt"); +#else + QFile::remove("tempfile.txt"); +#endif + +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + QDir().rmdir("./.hidden-directory"); + QFile::remove("link_to_tst_qfileinfo"); +#endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QDir().rmdir("./hidden-directory"); + QDir().rmdir("abs_symlink"); + QDir().rmdir("rel_symlink"); + QDir().rmdir("junction_pwd"); + QDir().rmdir("junction_root"); + QDir().rmdir("mountpoint"); + QFile::remove("abs_symlink.cpp"); + QFile::remove("rel_symlink.cpp"); +#endif +} + +// Testing get/set functions +void tst_QFileInfo::getSetCheck() +{ + QFileInfo obj1; + // bool QFileInfo::caching() + // void QFileInfo::setCaching(bool) + obj1.setCaching(false); + QCOMPARE(false, obj1.caching()); + obj1.setCaching(true); + QCOMPARE(true, obj1.caching()); +} + +static QFileInfoPrivate* getPrivate(QFileInfo &info) +{ + return (*reinterpret_cast<QFileInfoPrivate**>(&info)); +} + +void tst_QFileInfo::copy() +{ + QTemporaryFile *t; + t = new QTemporaryFile; + t->open(); + QFileInfo info(t->fileName()); + QVERIFY(info.exists()); + + //copy constructor + QFileInfo info2(info); + QFileInfoPrivate *privateInfo = getPrivate(info); + QFileInfoPrivate *privateInfo2 = getPrivate(info2); + QCOMPARE(privateInfo, privateInfo2); + + //operator = + QFileInfo info3 = info; + QFileInfoPrivate *privateInfo3 = getPrivate(info3); + QCOMPARE(privateInfo, privateInfo3); + QCOMPARE(privateInfo2, privateInfo3); + + //refreshing info3 will detach it + QFile file(info.absoluteFilePath()); + QVERIFY(file.open(QFile::WriteOnly)); + QCOMPARE(file.write("JAJAJAA"), qint64(7)); + file.flush(); + + QTest::qWait(250); +#if defined(Q_OS_WIN) || defined(Q_OS_WINCE) + if (QSysInfo::windowsVersion() & QSysInfo::WV_VISTA || + QSysInfo::windowsVersion() & QSysInfo::WV_CE_based) + file.close(); +#endif +#if defined(Q_OS_WINCE) + // On Windows CE we need to close the file. + // Otherwise the content will be cached and not + // flushed to the storage, although we flushed it + // manually!!! CE has interim cache, we cannot influence. + QTest::qWait(5000); +#endif + info3.refresh(); + privateInfo3 = getPrivate(info3); + QVERIFY(privateInfo != privateInfo3); + QVERIFY(privateInfo2 != privateInfo3); + QCOMPARE(privateInfo, privateInfo2); +} + +void tst_QFileInfo::isFile_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("data0") << QDir::currentPath() << false; + QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << true; + QTest::newRow("data2") << ":/tst_qfileinfo/resources/" << false; + QTest::newRow("data3") << ":/tst_qfileinfo/resources/file1" << true; + QTest::newRow("data4") << ":/tst_qfileinfo/resources/afilethatshouldnotexist" << false; +} + +void tst_QFileInfo::isFile() +{ + QFETCH(QString, path); + QFETCH(bool, expected); + + QFileInfo fi(path); + QCOMPARE(fi.isFile(), expected); +} + + +void tst_QFileInfo::isDir_data() +{ + // create a broken symlink + QFile::remove("brokenlink.lnk"); + QFile::remove("dummyfile"); + QFile file3("dummyfile"); + file3.open(QIODevice::WriteOnly); + if (file3.link("brokenlink.lnk")) { + file3.remove(); + QFileInfo info3("brokenlink.lnk"); + QVERIFY( info3.isSymLink() ); + } + + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("data0") << QDir::currentPath() << true; + QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << false; + QTest::newRow("data2") << ":/tst_qfileinfo/resources/" << true; + QTest::newRow("data3") << ":/tst_qfileinfo/resources/file1" << false; + QTest::newRow("data4") << ":/tst_qfileinfo/resources/afilethatshouldnotexist" << false; + + QTest::newRow("simple dir") << SRCDIR "resources" << true; + QTest::newRow("simple dir with slash") << SRCDIR "resources/" << true; + + QTest::newRow("broken link") << "brokenlink.lnk" << false; + +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("drive 1") << "c:" << true; + QTest::newRow("drive 2") << "c:/" << true; + //QTest::newRow("drive 2") << "t:s" << false; +#endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QTest::newRow("unc 1") << "//" + QtNetworkSettings::winServerName() << true; + QTest::newRow("unc 2") << "//" + QtNetworkSettings::winServerName() + "/" << true; + QTest::newRow("unc 3") << "//" + QtNetworkSettings::winServerName() + "/testshare" << true; + QTest::newRow("unc 4") << "//" + QtNetworkSettings::winServerName() + "/testshare/" << true; + QTest::newRow("unc 5") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp" << true; + QTest::newRow("unc 6") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp/" << true; + QTest::newRow("unc 7") << "//" + QtNetworkSettings::winServerName() + "/testshare/adirthatshouldnotexist" << false; +#endif +} + +void tst_QFileInfo::isDir() +{ + QFETCH(QString, path); + QFETCH(bool, expected); + + QFileInfo fi(path); + QCOMPARE(fi.isDir(), expected); +} + +void tst_QFileInfo::isRoot_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("expected"); + QTest::newRow("data0") << QDir::currentPath() << false; + QTest::newRow("data1") << "/" << true; + QTest::newRow("data2") << "*" << false; + QTest::newRow("data3") << "/*" << false; + QTest::newRow("data4") << ":/tst_qfileinfo/resources/" << false; + QTest::newRow("data5") << ":/" << true; + + QTest::newRow("simple dir") << SRCDIR "resources" << false; + QTest::newRow("simple dir with slash") << SRCDIR "resources/" << false; +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("drive 1") << "c:" << false; + QTest::newRow("drive 2") << "c:/" << true; + QTest::newRow("drive 3") << "p:/" << false; +#endif + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QTest::newRow("unc 1") << "//" + QtNetworkSettings::winServerName() << true; + QTest::newRow("unc 2") << "//" + QtNetworkSettings::winServerName() + "/" << true; + QTest::newRow("unc 3") << "//" + QtNetworkSettings::winServerName() + "/testshare" << false; + QTest::newRow("unc 4") << "//" + QtNetworkSettings::winServerName() + "/testshare/" << false; + QTest::newRow("unc 7") << "//ahostthatshouldnotexist" << false; +#endif +} + +void tst_QFileInfo::isRoot() +{ + QFETCH(QString, path); + QFETCH(bool, expected); + + QFileInfo fi(path); + QCOMPARE(fi.isRoot(), expected); +} + +void tst_QFileInfo::exists_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("data0") << QDir::currentPath() << true; + QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << true; + QTest::newRow("data2") << "/I/do_not_expect_this_path_to_exist/" << false; + QTest::newRow("data3") << ":/tst_qfileinfo/resources/" << true; + QTest::newRow("data4") << ":/tst_qfileinfo/resources/file1" << true; + QTest::newRow("data5") << ":/I/do_not_expect_this_path_to_exist/" << false; + QTest::newRow("data6") << SRCDIR "resources/*" << false; + QTest::newRow("data7") << SRCDIR "resources/*.foo" << false; + QTest::newRow("data8") << SRCDIR "resources/*.ext1" << false; + QTest::newRow("data9") << SRCDIR "resources/file?.ext1" << false; + QTest::newRow("data10") << "." << true; + QTest::newRow("data11") << ". " << false; + QTest::newRow("empty") << "" << false; + + QTest::newRow("simple dir") << SRCDIR "resources" << true; + QTest::newRow("simple dir with slash") << SRCDIR "resources/" << true; + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QTest::newRow("unc 1") << "//" + QtNetworkSettings::winServerName() << true; + QTest::newRow("unc 2") << "//" + QtNetworkSettings::winServerName() + "/" << true; + QTest::newRow("unc 3") << "//" + QtNetworkSettings::winServerName() + "/testshare" << true; + QTest::newRow("unc 4") << "//" + QtNetworkSettings::winServerName() + "/testshare/" << true; + QTest::newRow("unc 5") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp" << true; + QTest::newRow("unc 6") << "//" + QtNetworkSettings::winServerName() + "/testshare/tmp/" << true; + QTest::newRow("unc 7") << "//" + QtNetworkSettings::winServerName() + "/testshare/adirthatshouldnotexist" << false; + QTest::newRow("unc 8") << "//" + QtNetworkSettings::winServerName() + "/asharethatshouldnotexist" << false; + QTest::newRow("unc 9") << "//ahostthatshouldnotexist" << false; +#endif +} + +void tst_QFileInfo::exists() +{ + QFETCH(QString, path); + QFETCH(bool, expected); + + QFileInfo fi(path); + QCOMPARE(fi.exists(), expected); +} + +void tst_QFileInfo::absolutePath_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("filename"); + + QString drivePrefix; +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + drivePrefix = QDir::currentPath().left(2); + QString nonCurrentDrivePrefix = + drivePrefix.left(1).compare("X", Qt::CaseInsensitive) == 0 ? QString("Y:") : QString("X:"); + + // Make sure drive-relative paths return correct absolute paths (task 255326) + QTest::newRow("<current drive>:my.dll") << drivePrefix + "my.dll" << QDir::currentPath() << "my.dll"; + QTest::newRow("<not current drive>:my.dll") << nonCurrentDrivePrefix + "my.dll" + << nonCurrentDrivePrefix + "/" + << "my.dll"; +#endif + QTest::newRow("0") << "/machine/share/dir1/" << drivePrefix + "/machine/share/dir1" << ""; + QTest::newRow("1") << "/machine/share/dir1" << drivePrefix + "/machine/share" << "dir1"; + QTest::newRow("2") << "/usr/local/bin" << drivePrefix + "/usr/local" << "bin"; + QTest::newRow("3") << "/usr/local/bin/" << drivePrefix + "/usr/local/bin" << ""; + QTest::newRow("/test") << "/test" << drivePrefix + "/" << "test"; + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + // see task 102898 + QTest::newRow("c:\\autoexec.bat") << "c:\\autoexec.bat" << "C:/" + << "autoexec.bat"; +#endif +} + +void tst_QFileInfo::absolutePath() +{ + QFETCH(QString, file); + QFETCH(QString, path); + QFETCH(QString, filename); + + QFileInfo fi(file); + + QCOMPARE(fi.absolutePath(), path); + QCOMPARE(fi.fileName(), filename); +} + +void tst_QFileInfo::absFilePath_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("relativeFile") << "tmp.txt" << QDir::currentPath() + "/tmp.txt"; + QTest::newRow("relativeFileInSubDir") << "temp/tmp.txt" << QDir::currentPath() + "/" + "temp/tmp.txt"; +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QString curr = QDir::currentPath(); + + curr.remove(0, 2); // Make it a absolute path with no drive specifier: \depot\qt-4.2\tests\auto\qfileinfo + QTest::newRow(".") << curr << QDir::currentPath(); + QTest::newRow("absFilePath") << "c:\\home\\andy\\tmp.txt" << "C:/home/andy/tmp.txt"; + + // Make sure drive-relative paths return correct absolute paths (task 255326) + QString drivePrefix = QDir::currentPath().left(2); + QString nonCurrentDrivePrefix = + drivePrefix.left(1).compare("X", Qt::CaseInsensitive) == 0 ? QString("Y:") : QString("X:"); + + QTest::newRow("<current drive>:my.dll") << drivePrefix + "temp/my.dll" << QDir::currentPath() + "/temp/my.dll"; + QTest::newRow("<not current drive>:my.dll") << nonCurrentDrivePrefix + "temp/my.dll" + << nonCurrentDrivePrefix + "/temp/my.dll"; +#else + QTest::newRow("absFilePath") << "/home/andy/tmp.txt" << "/home/andy/tmp.txt"; +#endif +} + +void tst_QFileInfo::absFilePath() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QVERIFY(QString::compare(fi.absoluteFilePath(), expected, Qt::CaseInsensitive) == 0); +#else + QCOMPARE(fi.absoluteFilePath(), expected); +#endif +} + +void tst_QFileInfo::canonicalPath() +{ + QTemporaryFile tempFile; + tempFile.setAutoRemove(true); + tempFile.open(); + QFileInfo fi(tempFile.fileName()); + QCOMPARE(fi.canonicalPath(), QFileInfo(QDir::tempPath()).canonicalFilePath()); +} + +void tst_QFileInfo::canonicalFilePath() +{ + const QString fileName("tmp.canon"); + QFile tempFile(fileName); + QVERIFY(tempFile.open(QFile::WriteOnly)); + QFileInfo fi(tempFile.fileName()); + QCOMPARE(fi.canonicalFilePath(), QDir::currentPath() + "/" + fileName); + tempFile.remove(); + + // This used to crash on Mac, verify that it doesn't anymore. + QFileInfo info("/tmp/../../../../../../../../../../../../../../../../../"); + info.canonicalFilePath(); + +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + // This used to crash on Mac + QFileInfo dontCrash(QLatin1String("/")); + QCOMPARE(dontCrash.canonicalFilePath(), QLatin1String("/")); +#endif + +#ifndef Q_OS_WIN + // test symlinks + QFile::remove("link.lnk"); + { + QFile file(SRCDIR "tst_qfileinfo.cpp"); + if (file.link("link.lnk")) { + QFileInfo info1(file); + QFileInfo info2("link.lnk"); + QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath()); + } + } +# if !defined(Q_OS_SYMBIAN) + // Symbian doesn't support links to directories + { + const QString link(QDir::tempPath() + QDir::separator() + "tst_qfileinfo"); + QFile::remove(link); + QFile file(QDir::currentPath()); + if (file.link(link)) { + QFile tempfile("tempfile.txt"); + tempfile.open(QIODevice::ReadWrite); + tempfile.write("This file is generated by the QFileInfo autotest."); + QVERIFY(tempfile.flush()); + tempfile.close(); + + QFileInfo info1("tempfile.txt"); + QFileInfo info2(link + QDir::separator() + "tempfile.txt"); + + QVERIFY(info1.exists()); + QVERIFY(info2.exists()); + QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath()); + + QFileInfo info3(link + QDir::separator() + "link.lnk"); + QFileInfo info4(SRCDIR "tst_qfileinfo.cpp"); + QVERIFY(!info3.canonicalFilePath().isEmpty()); + QCOMPARE(info4.canonicalFilePath(), info3.canonicalFilePath()); + + tempfile.remove(); + } + } + { + QString link(QDir::tempPath() + QDir::separator() + "tst_qfileinfo" + + QDir::separator() + "link_to_tst_qfileinfo"); + QFile::remove(link); + + QFile file(QDir::tempPath() + QDir::separator() + "tst_qfileinfo" + + QDir::separator() + "tst_qfileinfo.cpp"); + if (file.link(link)) + { + QFileInfo info1("tst_qfileinfo.cpp"); + QFileInfo info2(link); + QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath()); + } + } +# endif +#endif + +#ifdef Q_OS_WIN + typedef BOOL (WINAPI *PtrCreateSymbolicLink)(LPTSTR, LPTSTR, DWORD); + PtrCreateSymbolicLink ptrCreateSymbolicLink = + (PtrCreateSymbolicLink)QLibrary::resolve(QLatin1String("kernel32"), "CreateSymbolicLinkW"); + + if (!ptrCreateSymbolicLink) { + QSKIP("Symbolic links aren't supported by FS", SkipAll); + } else { + // CreateSymbolicLink can return TRUE & still fail to create the link, + // the error code in that case is ERROR_PRIVILEGE_NOT_HELD (1314) + SetLastError(0); + BOOL ret = ptrCreateSymbolicLink((wchar_t*)QString("res").utf16(), (wchar_t*)QString("resources").utf16(), 1); + DWORD dwErr = GetLastError(); + if (!ret) + QSKIP("Symbolic links aren't supported by FS", SkipAll); + QString currentPath = QDir::currentPath(); + bool is_res_Current = QDir::setCurrent("res"); + if (!is_res_Current && dwErr == 1314) + QSKIP("Not enough privilages to create Symbolic links", SkipAll); + QCOMPARE(is_res_Current, true); + + QCOMPARE(QFileInfo("file1").canonicalFilePath(), currentPath + "/resources/file1"); + + QCOMPARE(QDir::setCurrent(currentPath), true); + QDir::current().rmdir("res"); + } +#endif +} + +void tst_QFileInfo::fileName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("relativeFile") << "tmp.txt" << "tmp.txt"; + QTest::newRow("relativeFileInSubDir") << "temp/tmp.txt" << "tmp.txt"; +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + QTest::newRow("absFilePath") << "c:\\home\\andy\\tmp.txt" << "tmp.txt"; +#else + QTest::newRow("absFilePath") << "/home/andy/tmp.txt" << "tmp.txt"; +#endif + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "file1.ext1"; + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "file1.ext1.ext2"; + + QTest::newRow("ending slash [small]") << QString::fromLatin1("/a/") << QString::fromLatin1(""); + QTest::newRow("no ending slash [small]") << QString::fromLatin1("/a") << QString::fromLatin1("a"); + + QTest::newRow("ending slash") << QString::fromLatin1("/somedir/") << QString::fromLatin1(""); + QTest::newRow("no ending slash") << QString::fromLatin1("/somedir") << QString::fromLatin1("somedir"); +} + +void tst_QFileInfo::fileName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); + QCOMPARE(fi.fileName(), expected); +} + +void tst_QFileInfo::bundleName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("root") << "/" << ""; + QTest::newRow("etc") << "/etc" << ""; +#ifdef Q_OS_MAC + QTest::newRow("safari") << "/Applications/Safari.app" << "Safari"; +#endif +} + +void tst_QFileInfo::bundleName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); + QCOMPARE(fi.bundleName(), expected); +} + +void tst_QFileInfo::dir_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<bool>("absPath"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("relativeFile") << "tmp.txt" << false << "."; + QTest::newRow("relativeFileAbsPath") << "tmp.txt" << true << QDir::currentPath(); + QTest::newRow("relativeFileInSubDir") << "temp/tmp.txt" << false << "temp"; + QTest::newRow("relativeFileInSubDirAbsPath") << "temp/tmp.txt" << true << QDir::currentPath() + "/temp"; + QTest::newRow("absFilePath") << QDir::currentPath() + "/tmp.txt" << false << QDir::currentPath(); + QTest::newRow("absFilePathAbsPath") << QDir::currentPath() + "/tmp.txt" << true << QDir::currentPath(); + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << true << ":/tst_qfileinfo/resources"; +} + +void tst_QFileInfo::dir() +{ + QFETCH(QString, file); + QFETCH(bool, absPath); + QFETCH(QString, expected); + + QFileInfo fi(file); + if (absPath) { + QCOMPARE(fi.absolutePath(), expected); + QCOMPARE(fi.absoluteDir().path(), expected); + } else { + QCOMPARE(fi.path(), expected); + QCOMPARE(fi.dir().path(), expected); + } +} + + +void tst_QFileInfo::suffix_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("noextension0") << "file" << ""; + QTest::newRow("noextension1") << "/path/to/file" << ""; + QTest::newRow("data0") << "file.tar" << "tar"; + QTest::newRow("data1") << "file.tar.gz" << "gz"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "gz"; + QTest::newRow("data3") << "/path/file.tar" << "tar"; + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "ext1"; + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "ext2"; + QTest::newRow("hidden1") << ".ext1" << "ext1"; + QTest::newRow("hidden1") << ".ext" << "ext"; + QTest::newRow("hidden1") << ".ex" << "ex"; + QTest::newRow("hidden1") << ".e" << "e"; + QTest::newRow("hidden2") << ".ext1.ext2" << "ext2"; + QTest::newRow("hidden2") << ".ext.ext2" << "ext2"; + QTest::newRow("hidden2") << ".ex.ext2" << "ext2"; + QTest::newRow("hidden2") << ".e.ext2" << "ext2"; + QTest::newRow("hidden2") << "..ext2" << "ext2"; +} + +void tst_QFileInfo::suffix() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); + QCOMPARE(fi.suffix(), expected); +} + + +void tst_QFileInfo::completeSuffix_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("noextension0") << "file" << ""; + QTest::newRow("noextension1") << "/path/to/file" << ""; + QTest::newRow("data0") << "file.tar" << "tar"; + QTest::newRow("data1") << "file.tar.gz" << "tar.gz"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "tar.gz"; + QTest::newRow("data3") << "/path/file.tar" << "tar"; + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "ext1"; + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "ext1.ext2"; +} + +void tst_QFileInfo::completeSuffix() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); + QCOMPARE(fi.completeSuffix(), expected); +} + +void tst_QFileInfo::baseName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("data0") << "file.tar" << "file"; + QTest::newRow("data1") << "file.tar.gz" << "file"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "file"; + QTest::newRow("data3") << "/path/file.tar" << "file"; + QTest::newRow("data4") << "/path/file" << "file"; + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "file1"; + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "file1"; +} + +void tst_QFileInfo::baseName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); + QCOMPARE(fi.baseName(), expected); +} + +void tst_QFileInfo::completeBaseName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("data0") << "file.tar" << "file"; + QTest::newRow("data1") << "file.tar.gz" << "file.tar"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "file.tar"; + QTest::newRow("data3") << "/path/file.tar" << "file"; + QTest::newRow("data4") << "/path/file" << "file"; + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "file1"; + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "file1.ext1"; +} + +void tst_QFileInfo::completeBaseName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); + QCOMPARE(fi.completeBaseName(), expected); +} + +void tst_QFileInfo::permission_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<int>("perms"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("data0") << QCoreApplication::instance()->applicationFilePath() << int(QFile::ExeUser) << true; + QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << int(QFile::ReadUser) << true; +// QTest::newRow("data2") << "tst_qfileinfo.cpp" << int(QFile::WriteUser) << false; + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << int(QFile::ReadUser) << true; + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1" << int(QFile::WriteUser) << false; + QTest::newRow("resource3") << ":/tst_qfileinfo/resources/file1.ext1" << int(QFile::ExeUser) << false; +} + +void tst_QFileInfo::permission() +{ + QFETCH(QString, file); + QFETCH(int, perms); + QFETCH(bool, expected); +#ifdef Q_OS_SYMBIAN + QSKIP("No user based rights in Symbian OS - SOS needs platform security tests instead", SkipAll); +#endif + QFileInfo fi(file); + QCOMPARE(fi.permission(QFile::Permissions(perms)), expected); +} + +void tst_QFileInfo::size_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<int>("size"); + + QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << 0; + QFile::remove("file1"); + QFile file("file1"); + QVERIFY(file.open(QFile::WriteOnly)); + QCOMPARE(file.write("JAJAJAA"), qint64(7)); + QTest::newRow("created-file") << "file1" << 7; + + QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << 0; +} + +void tst_QFileInfo::size() +{ + QFETCH(QString, file); + + QFileInfo fi(file); + (void)fi.permissions(); // see task 104198 + QTEST(int(fi.size()), "size"); +} + +void tst_QFileInfo::systemFiles() +{ +#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) + QSKIP("This is a Windows only test", SkipAll); +#endif + QFileInfo fi("c:\\pagefile.sys"); + QVERIFY(fi.exists()); // task 167099 + QVERIFY(fi.size() > 0); // task 189202 + QVERIFY(fi.lastModified().isValid()); +} + +void tst_QFileInfo::compare_data() +{ + QTest::addColumn<QString>("file1"); + QTest::addColumn<QString>("file2"); + QTest::addColumn<bool>("same"); + +#if defined(Q_OS_MAC) + // Since 10.6 we use realpath() in qfsfileengine, and it properly handles + // file system case sensitivity. However here in the autotest we don't + // check if the file system is case sensitive, so to make it pass in the + // default OS X installation we assume we are running on a case insensitive + // file system if on 10.6 and on a case sensitive file system if on 10.5 + bool caseSensitiveOnMac = true; + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) + caseSensitiveOnMac = false; +#endif + + QTest::newRow("data0") + << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp") + << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp") + << true; + QTest::newRow("data1") + << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp") + << QString::fromLatin1("/tst_qfileinfo.cpp") + << false; + QTest::newRow("data2") + << QString::fromLatin1("tst_qfileinfo.cpp") + << QDir::currentPath() + QString::fromLatin1("/tst_qfileinfo.cpp") + << true; + QTest::newRow("casesense1") + << QString::fromLatin1(SRCDIR "tst_qfileInfo.cpp") + << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp") +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + << true; +#elif defined(Q_OS_MAC) + << !caseSensitiveOnMac; +#else + << false; +#endif +} + +void tst_QFileInfo::compare() +{ + QFETCH(QString, file1); + QFETCH(QString, file2); + QFETCH(bool, same); + QFileInfo fi1(file1), fi2(file2); + QCOMPARE(fi1 == fi2, same); +} + +void tst_QFileInfo::consistent_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QTest::newRow("slashes") << QString::fromLatin1("\\a\\a\\a\\a") << QString::fromLatin1("/a/a/a/a"); +#endif + QTest::newRow("ending slash") << QString::fromLatin1("/a/somedir/") << QString::fromLatin1("/a/somedir/"); + QTest::newRow("no ending slash") << QString::fromLatin1("/a/somedir") << QString::fromLatin1("/a/somedir"); +} + +void tst_QFileInfo::consistent() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileInfo fi(file); + QCOMPARE(fi.filePath(), expected); + QCOMPARE(fi.dir().path() + "/" + fi.fileName(), expected); +} + + +void tst_QFileInfo::fileTimes_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::newRow("simple") << QString::fromLatin1("simplefile.txt"); + QTest::newRow( "longfile" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName.txt"); + QTest::newRow( "longfile absolutepath" ) << QFileInfo(QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName" + "longFileNamelongFileNamelongFileNamelongFileName.txt")).absoluteFilePath(); +} + +void tst_QFileInfo::fileTimes() +{ +#if defined(Q_OS_WINCE) + int sleepTime = 3000; +#else + int sleepTime = 2000; +#endif + QFETCH(QString, fileName); + if (QFile::exists(fileName)) { + QVERIFY(QFile::remove(fileName)); + } + QTest::qSleep(sleepTime); + { + QFile file(fileName); +#if defined(Q_OS_WINCE) + QEXPECT_FAIL("longfile", "No long filenames on WinCE", Abort); + QEXPECT_FAIL("longfile absolutepath", "No long filenames on WinCE", Abort); +#elif defined(Q_OS_SYMBIAN) + QEXPECT_FAIL("longfile", "Maximum total filepath cannot exceed 256 characters in Symbian", Abort); + QEXPECT_FAIL("longfile absolutepath", "Maximum total filepath cannot exceed 256 characters in Symbian", Abort); +#endif + QVERIFY(file.open(QFile::WriteOnly | QFile::Text)); +#ifdef Q_OS_UNIX + if (qIsLikelyToBeNfs(file.handle())) + QSKIP("This Test doesn't work on NFS", SkipAll); +#endif + QTextStream ts(&file); + ts << fileName << endl; + } + QTest::qSleep(sleepTime); + QDateTime beforeWrite = QDateTime::currentDateTime(); + QTest::qSleep(sleepTime); + { + QFileInfo fileInfo(fileName); + QVERIFY(fileInfo.created() < beforeWrite); + QFile file(fileName); + QVERIFY(file.open(QFile::ReadWrite | QFile::Text)); + QTextStream ts(&file); + ts << fileName << endl; + } + QTest::qSleep(sleepTime); + QDateTime beforeRead = QDateTime::currentDateTime(); + QTest::qSleep(sleepTime); + { + QFileInfo fileInfo(fileName); +// On unix created() returns the same as lastModified(). +#if !defined(Q_OS_UNIX) && !defined(Q_OS_WINCE) + QVERIFY(fileInfo.created() < beforeWrite); +#endif + QVERIFY(fileInfo.lastModified() > beforeWrite); + QFile file(fileName); + QVERIFY(file.open(QFile::ReadOnly | QFile::Text)); + QTextStream ts(&file); + QString line = ts.readLine(); + QCOMPARE(line, fileName); + } + + QFileInfo fileInfo(fileName); +#if !defined(Q_OS_UNIX) && !defined(Q_OS_WINCE) + QVERIFY(fileInfo.created() < beforeWrite); +#endif + //In Vista the last-access timestamp is not updated when the file is accessed/touched (by default). + //To enable this the HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate + //is set to 0, in the test machine. +#ifdef Q_OS_WINCE + QEXPECT_FAIL("simple", "WinCE only stores date of access data, not the time", Continue); +#endif +#ifdef Q_OS_SYMBIAN + QEXPECT_FAIL("simple", "Symbian implementation of stat doesn't return read time right", Abort); +#endif + QVERIFY(fileInfo.lastRead() > beforeRead); + QVERIFY(fileInfo.lastModified() > beforeWrite); + QVERIFY(fileInfo.lastModified() < beforeRead); +} + +void tst_QFileInfo::fileTimes_oldFile() +{ + // This is not supported on WinCE +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + // All files are opened in share mode (both read and write). + DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + // All files on Windows can be read; there's no such thing as an + // unreadable file. Add GENERIC_WRITE if WriteOnly is passed. + int accessRights = GENERIC_READ | GENERIC_WRITE; + + SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + + // Regular file mode. In Unbuffered mode, pass the no-buffering flag. + DWORD flagsAndAtts = FILE_ATTRIBUTE_NORMAL; + + // WriteOnly can create files, ReadOnly cannot. + DWORD creationDisp = OPEN_ALWAYS; + + // Create the file handle. + HANDLE fileHandle = CreateFile(L"oldfile.txt", + accessRights, + shareMode, + &securityAtts, + creationDisp, + flagsAndAtts, + NULL); + + // Set file times back to 1601. + SYSTEMTIME stime; + stime.wYear = 1601; + stime.wMonth = 1; + stime.wDayOfWeek = 1; + stime.wDay = 1; + stime.wHour = 1; + stime.wMinute = 0; + stime.wSecond = 0; + stime.wMilliseconds = 0; + + FILETIME ctime; + QVERIFY(SystemTimeToFileTime(&stime, &ctime)); + FILETIME atime = ctime; + FILETIME mtime = atime; + QVERIFY(fileHandle); + QVERIFY(SetFileTime(fileHandle, &ctime, &atime, &mtime) != 0); + + CloseHandle(fileHandle); + + QFileInfo info("oldfile.txt"); + QCOMPARE(info.lastModified(), QDateTime(QDate(1601, 1, 1), QTime(1, 0), Qt::UTC).toLocalTime()); +#endif +} + +void tst_QFileInfo::isSymLink_data() +{ +#ifndef NO_SYMLINKS + QFile::remove("link.lnk"); + QFile::remove("brokenlink.lnk"); + QFile::remove("dummyfile"); + + QFile file1(SRCDIR "tst_qfileinfo.cpp"); + QVERIFY(file1.link("link.lnk")); + + QFile file2("dummyfile"); + file2.open(QIODevice::WriteOnly); + QVERIFY(file2.link("brokenlink.lnk")); + file2.remove(); + + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isSymLink"); + QTest::addColumn<QString>("linkTarget"); + + QTest::newRow("existent file") << SRCDIR "tst_qfileinfo.cpp" << false << ""; + QTest::newRow("link") << "link.lnk" << true << QFileInfo(SRCDIR "tst_qfileinfo.cpp").absoluteFilePath(); + QTest::newRow("broken link") << "brokenlink.lnk" << true << QFileInfo("dummyfile").absoluteFilePath(); +#endif +} + +void tst_QFileInfo::isSymLink() +{ +#ifndef NO_SYMLINKS + QFETCH(QString, path); + QFETCH(bool, isSymLink); + QFETCH(QString, linkTarget); + + QFileInfo fi(path); + QCOMPARE(fi.isSymLink(), isSymLink); + QCOMPARE(fi.symLinkTarget(), linkTarget); +#else + QSKIP("no symbolic link support on this platform", SkipAll); +#endif +} + +void tst_QFileInfo::isHidden_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isHidden"); + foreach (const QFileInfo& info, QDir::drives()) { + QTest::newRow(qPrintable("drive." + info.path())) << info.path() << false; + } + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QVERIFY(QDir("./hidden-directory").exists() || QDir().mkdir("./hidden-directory")); + QVERIFY(SetFileAttributesW(reinterpret_cast<LPCWSTR>(QString("./hidden-directory").utf16()),FILE_ATTRIBUTE_HIDDEN)); + QTest::newRow("C:/path/to/hidden-directory") << QDir::currentPath() + QString::fromLatin1("/hidden-directory") << true; + QTest::newRow("C:/path/to/hidden-directory/.") << QDir::currentPath() + QString::fromLatin1("/hidden-directory/.") << true; +#endif +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + QVERIFY(QDir("./.hidden-directory").exists() || QDir().mkdir("./.hidden-directory")); + QTest::newRow("/path/to/.hidden-directory") << QDir::currentPath() + QString("/.hidden-directory") << true; + QTest::newRow("/path/to/.hidden-directory/.") << QDir::currentPath() + QString("/.hidden-directory/.") << true; + QTest::newRow("/path/to/.hidden-directory/..") << QDir::currentPath() + QString("/.hidden-directory/..") << true; +#endif + +#if defined(Q_OS_MAC) + // /bin has the hidden attribute on Mac OS X + QTest::newRow("/bin/") << QString::fromLatin1("/bin/") << true; +#elif !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) + QTest::newRow("/bin/") << QString::fromLatin1("/bin/") << false; +#endif + +#ifdef Q_OS_MAC + QTest::newRow("mac_etc") << QString::fromLatin1("/etc") << true; + QTest::newRow("mac_private_etc") << QString::fromLatin1("/private/etc") << false; + QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications") << false; +#endif + +#ifdef Q_OS_SYMBIAN + // No guaranteed hidden file knows to exist in Symbian filesystem, so make one. + QString hiddenFileName("hidden.txt"); + QString notHiddenFileName("nothidden.txt"); + QTest::newRow("hidden file") << hiddenFileName << true; + QTest::newRow("non-hidden file") << notHiddenFileName << false; + + { + QFile file(hiddenFileName); + QVERIFY(file.open(QIODevice::WriteOnly)); + QTextStream t(&file); + t << "foobar"; + + QFile file2(notHiddenFileName); + QVERIFY(file2.open(QIODevice::WriteOnly)); + QTextStream t2(&file2); + t2 << "foobar"; + } + + RFs rfs; + TInt err = rfs.Connect(); + QCOMPARE(err, KErrNone); + HBufC* symFile = qt_QString2HBufC(hiddenFileName); + err = rfs.SetAtt(*symFile, KEntryAttHidden, 0); + rfs.Close(); + delete symFile; + QCOMPARE(err, KErrNone); +#endif +} + +void tst_QFileInfo::isHidden() +{ + QFETCH(QString, path); + QFETCH(bool, isHidden); + QFileInfo fi(path); + + QCOMPARE(fi.isHidden(), isHidden); +} + +#if defined(Q_OS_MAC) +void tst_QFileInfo::isHiddenFromFinder() +{ + const char *filename = "test_foobar.txt"; + + QFile testFile(filename); + testFile.open(QIODevice::WriteOnly | QIODevice::Append); + testFile.write(QByteArray("world")); + testFile.close(); + + struct stat buf; + stat(filename, &buf); + chflags(filename, buf.st_flags | UF_HIDDEN); + + QFileInfo fi(filename); + QCOMPARE(fi.isHidden(), true); + + testFile.remove(); +} +#endif + +void tst_QFileInfo::isBundle_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isBundle"); + QTest::newRow("root") << QString::fromLatin1("/") << false; +#ifdef Q_OS_MAC + QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications") << false; + QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications/Safari.app") << true; +#endif +} + +void tst_QFileInfo::isBundle() +{ + QFETCH(QString, path); + QFETCH(bool, isBundle); + QFileInfo fi(path); + QCOMPARE(fi.isBundle(), isBundle); +} + +void tst_QFileInfo::isLocalFs_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isLocalFs"); + + QTest::newRow("local root") << QString::fromLatin1("/") << true; + QTest::newRow("local non-existent file") << QString::fromLatin1("/abrakadabra.boo") << true; + + QTest::newRow("qresource root") << QString::fromLatin1(":/") << false; +} + +void tst_QFileInfo::isLocalFs() +{ + QFETCH(QString, path); + QFETCH(bool, isLocalFs); + + QFileInfo info(path); + QFileInfoPrivate *privateInfo = getPrivate(info); + QCOMPARE((privateInfo->fileEngine == 0), isLocalFs); + if (privateInfo->fileEngine) + QCOMPARE(bool(privateInfo->fileEngine->fileFlags(QAbstractFileEngine::LocalDiskFlag) + & QAbstractFileEngine::LocalDiskFlag), isLocalFs); +} + +void tst_QFileInfo::refresh() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_WIN) + int sleepTime = 3000; +#else + int sleepTime = 2000; +#endif + + QFile::remove("file1"); + QFile file("file1"); + QVERIFY(file.open(QFile::WriteOnly)); + QCOMPARE(file.write("JAJAJAA"), qint64(7)); + file.flush(); + + QFileInfo info(file); + QDateTime lastModified = info.lastModified(); + QCOMPARE(info.size(), qint64(7)); + + QTest::qSleep(sleepTime); + + QCOMPARE(file.write("JOJOJO"), qint64(6)); + file.flush(); + QVERIFY(info.lastModified() == lastModified); + + QCOMPARE(info.size(), qint64(7)); +#if defined(Q_OS_WIN) || defined(Q_OS_WINCE) + if (QSysInfo::windowsVersion() & QSysInfo::WV_VISTA || + QSysInfo::windowsVersion() & QSysInfo::WV_CE_based) + file.close(); +#endif +#if defined(Q_OS_WINCE) + // On Windows CE we need to close the file. + // Otherwise the content will be cached and not + // flushed to the storage, although we flushed it + // manually!!! CE has interim cache, we cannot influence. + QTest::qWait(5000); +#endif + info.refresh(); + QCOMPARE(info.size(), qint64(13)); + QVERIFY(info.lastModified() > lastModified); + + QFileInfo info2 = info; + QCOMPARE(info2.size(), info.size()); + + info2.refresh(); + QCOMPARE(info2.size(), info.size()); +} + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isSymLink"); + QTest::addColumn<QString>("linkTarget"); + QTest::addColumn<QString>("canonicalFilePath"); + + QDir pwd; + pwd.mkdir("target"); + + QLibrary kernel32("kernel32"); + typedef BOOLEAN (WINAPI *PtrCreateSymbolicLink)(LPCWSTR, LPCWSTR, DWORD); + PtrCreateSymbolicLink createSymbolicLinkW = 0; + createSymbolicLinkW = (PtrCreateSymbolicLink) kernel32.resolve("CreateSymbolicLinkW"); + if (!createSymbolicLinkW) { + //we need at least one data set for the test not to fail when skipping _data function + QDir target("target"); + QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath(); + QSKIP("symbolic links not supported by operating system",SkipSingle); + } + { + //Directory symlinks + QDir target("target"); + QVERIFY(target.exists()); + + QString absTarget = QDir::toNativeSeparators(target.absolutePath()); + QString absSymlink = QDir::toNativeSeparators(pwd.absolutePath()).append("\\abs_symlink"); + QString relTarget = "target"; + QString relSymlink = "rel_symlink"; + QString fileInTarget(absTarget); + fileInTarget.append("\\file"); + QString fileInSymlink(absSymlink); + fileInSymlink.append("\\file"); + QFile file(fileInTarget); + file.open(QIODevice::ReadWrite); + file.close(); + + DWORD err = ERROR_SUCCESS ; + if (!pwd.exists("abs_symlink")) + if (!createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1)) + err = GetLastError(); + if (err == ERROR_SUCCESS && !pwd.exists(relSymlink)) + if (!createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1)) + err = GetLastError(); + if (err != ERROR_SUCCESS) { + wchar_t errstr[0x100]; + DWORD count = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, + 0, err, 0, errstr, 0x100, 0); + QString error(QString::fromUtf16(errstr, count)); + qWarning() << error; + //we need at least one data set for the test not to assert fail when skipping _data function + QDir target("target"); + QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath(); + QSKIP("link not supported by FS or insufficient privilege", SkipSingle); + } + QVERIFY(file.exists()); + + QTest::newRow("absolute dir symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalPath(); + QTest::newRow("relative dir symlink") << relSymlink << true << QDir::fromNativeSeparators(relTarget) << target.canonicalPath(); + QTest::newRow("file in symlink dir") << fileInSymlink << false << "" << target.canonicalPath().append("/file"); + } + { + //File symlinks + QFileInfo target(SRCDIR "tst_qfileinfo.cpp"); + QString absTarget = QDir::toNativeSeparators(target.absoluteFilePath()); + QString absSymlink = QDir::toNativeSeparators(pwd.absolutePath()).append("\\abs_symlink.cpp"); + QString relTarget = QDir::toNativeSeparators(pwd.relativeFilePath(target.absoluteFilePath())); + QString relSymlink = "rel_symlink.cpp"; + QVERIFY(pwd.exists("abs_symlink.cpp") || createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x0)); + QVERIFY(pwd.exists(relSymlink) || createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x0)); + + QTest::newRow("absolute file symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); + QTest::newRow("relative file symlink") << relSymlink << true << QDir::fromNativeSeparators(relTarget) << target.canonicalFilePath(); + } + + //Junctions + QString target = "target"; + QString junction = "junction_pwd"; + FileSystem::createNtfsJunction(target, junction); + QFileInfo targetInfo(target); + QTest::newRow("junction_pwd") << junction << true << targetInfo.absoluteFilePath() << targetInfo.canonicalFilePath(); + + QFileInfo fileInJunction(targetInfo.absoluteFilePath().append("/file")); + QFile file(fileInJunction.absoluteFilePath()); + file.open(QIODevice::ReadWrite); + file.close(); + QVERIFY(file.exists()); + QTest::newRow("file in junction") << fileInJunction.absoluteFilePath() << false << "" << fileInJunction.canonicalFilePath(); + + target = QDir::rootPath(); + junction = "junction_root"; + FileSystem::createNtfsJunction(target, junction); + targetInfo.setFile(target); + QTest::newRow("junction_root") << junction << true << targetInfo.absoluteFilePath() << targetInfo.canonicalFilePath(); + + //Mountpoint + typedef BOOLEAN (WINAPI *PtrGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD); + PtrGetVolumeNameForVolumeMountPointW getVolumeNameForVolumeMountPointW = 0; + getVolumeNameForVolumeMountPointW = (PtrGetVolumeNameForVolumeMountPointW) kernel32.resolve("GetVolumeNameForVolumeMountPointW"); + if(getVolumeNameForVolumeMountPointW) + { + wchar_t buffer[MAX_PATH]; + QString rootPath = QDir::toNativeSeparators(QDir::rootPath()); + QVERIFY(getVolumeNameForVolumeMountPointW((wchar_t*)rootPath.utf16(), buffer, MAX_PATH)); + QString rootVolume = QString::fromWCharArray(buffer); + junction = "mountpoint"; + rootVolume.replace("\\\\?\\","\\??\\"); + FileSystem::createNtfsJunction(rootVolume, junction); + QTest::newRow("mountpoint") << junction << true << QDir::fromNativeSeparators(rootPath) << QDir::rootPath(); + } +} + +void tst_QFileInfo::ntfsJunctionPointsAndSymlinks() +{ + QFETCH(QString, path); + QFETCH(bool, isSymLink); + QFETCH(QString, linkTarget); + QFETCH(QString, canonicalFilePath); + + QFileInfo fi(path); + QCOMPARE(fi.isSymLink(), isSymLink); + QCOMPARE(fi.symLinkTarget(), linkTarget); + QCOMPARE(fi.canonicalFilePath(), canonicalFilePath); +} + +void tst_QFileInfo::brokenShortcut() +{ + QString linkName("borkenlink.lnk"); + QFile::remove(linkName); + QFile file(linkName); + file.open(QFile::WriteOnly); + file.write("b0rk"); + file.close(); + + QFileInfo info(linkName); + QVERIFY(info.isSymLink()); + QVERIFY(!info.exists()); + QFile::remove(linkName); +} +#endif + +void tst_QFileInfo::isWritable() +{ + QFile tempfile("tempfile.txt"); + tempfile.open(QIODevice::WriteOnly); + tempfile.write("This file is generated by the QFileInfo autotest."); + tempfile.close(); + + QVERIFY(QFileInfo("tempfile.txt").isWritable()); + tempfile.remove(); + +#ifdef Q_OS_WIN +#ifdef Q_OS_WINCE + QFileInfo fi("\\Windows\\wince.nls"); +#else + QFileInfo fi("c:\\pagefile.sys"); +#endif + QVERIFY(fi.exists()); + QVERIFY(!fi.isWritable()); +#endif +#if defined (Q_OS_UNIX) && !defined (Q_OS_SYMBIAN) + if (::getuid() == 0) + QVERIFY(QFileInfo("/etc/passwd").isWritable()); + else + QVERIFY(!QFileInfo("/etc/passwd").isWritable()); +#endif +} + +void tst_QFileInfo::isExecutable() +{ +#ifdef Q_OS_SYMBIAN + QString appPath = "c:/sys/bin/tst_qfileinfo.exe"; +#else + QString appPath = QCoreApplication::applicationDirPath(); + appPath += "/tst_qfileinfo"; +# if defined(Q_OS_WIN) + appPath += ".exe"; +# endif +#endif + QFileInfo fi(appPath); + QCOMPARE(fi.isExecutable(), true); + + QCOMPARE(QFileInfo("qfileinfo.pro").isExecutable(), false); +} + + +void tst_QFileInfo::testDecomposedUnicodeNames_data() +{ + QTest::addColumn<QString>("filePath"); + QTest::addColumn<QString>("fileName"); + QTest::addColumn<bool>("exists"); + QString currPath = QDir::currentPath(); + QTest::newRow("latin-only") << currPath + "/4.pdf" << "4.pdf" << true; + QTest::newRow("one-decomposed uni") << currPath + QString::fromUtf8("/4 À.pdf") << QString::fromUtf8("4 À.pdf") << true; + QTest::newRow("many-decomposed uni") << currPath + QString::fromUtf8("/4 ÀÀÀcopy.pdf") << QString::fromUtf8("4 ÀÀÀcopy.pdf") << true; + QTest::newRow("no decomposed") << currPath + QString::fromUtf8("/4 ÞÞÞcopy.pdf") << QString::fromUtf8("4 ÞÞÞcopy.pdf") << true; +} + +static void createFileNative(const QString &filePath) +{ +#ifdef Q_OS_UNIX + int fd = open(filePath.normalized(QString::NormalizationForm_D).toUtf8().constData(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd < 0) { + QFAIL("couldn't create file"); + } else { + close(fd); + } +#else + Q_UNUSED(filePath); +#endif +} + +static void removeFileNative(const QString &filePath) +{ +#ifdef Q_OS_UNIX + unlink(filePath.normalized(QString::NormalizationForm_D).toUtf8().constData()); +#else + Q_UNUSED(filePath); +#endif +} + +void tst_QFileInfo::testDecomposedUnicodeNames() +{ +#ifndef Q_OS_MAC + QSKIP("This is a OS X only test (unless you know more about filesystems, then maybe you should try it ;)", SkipAll); +#endif + QFETCH(QString, filePath); + createFileNative(filePath); + + QFileInfo file(filePath); + QTEST(file.fileName(), "fileName"); + QTEST(file.exists(), "exists"); + removeFileNative(filePath); +} + +void tst_QFileInfo::equalOperator() const +{ + /* Compare two default constructed values. Yes, to me it seems it should be the opposite too, but + * this is how the code was written. */ + QVERIFY(!(QFileInfo() == QFileInfo())); +} + + +void tst_QFileInfo::equalOperatorWithDifferentSlashes() const +{ + const QFileInfo fi1("/usr"); + const QFileInfo fi2("/usr/"); + + QCOMPARE(fi1, fi2); +} + +void tst_QFileInfo::notEqualOperator() const +{ + /* Compare two default constructed values. Yes, to me it seems it should be the opposite too, but + * this is how the code was written. */ + QVERIFY(QFileInfo() != QFileInfo()); +} + +void tst_QFileInfo::detachingOperations() +{ + QFileInfo info1; + QVERIFY(info1.caching()); + info1.setCaching(false); + + { + QFileInfo info2 = info1; + + QVERIFY(!info1.caching()); + QVERIFY(!info2.caching()); + + info2.setCaching(true); + QVERIFY(info2.caching()); + + info1.setFile("foo"); + QVERIFY(!info1.caching()); + } + + { + QFile file("foo"); + info1.setFile(file); + QVERIFY(!info1.caching()); + } + + info1.setFile(QDir(), "foo"); + QVERIFY(!info1.caching()); + + { + QFileInfo info3; + QVERIFY(info3.caching()); + + info3 = info1; + QVERIFY(!info3.caching()); + } + + info1.refresh(); + QVERIFY(!info1.caching()); + + QVERIFY(info1.makeAbsolute()); + QVERIFY(!info1.caching()); + + info1.detach(); + QVERIFY(!info1.caching()); +} + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) +#if defined (Q_OS_WIN) +BOOL IsUserAdmin() +{ + BOOL b; + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + PSID AdministratorsGroup; + b = AllocateAndInitializeSid( + &NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdministratorsGroup); + if (b) { + if (!CheckTokenMembership( NULL, AdministratorsGroup, &b)) + b = FALSE; + FreeSid(AdministratorsGroup); + } + + return(b); +} +#endif + +void tst_QFileInfo::owner() +{ + QString userName; +#if defined(Q_OS_UNIX) + { + passwd *user = getpwuid(geteuid()); + QVERIFY(user); + char *usernameBuf = user->pw_name; + userName = QString::fromLocal8Bit(usernameBuf); + } +#endif +#if defined(Q_OS_WIN) + wchar_t usernameBuf[1024]; + DWORD bufSize = 1024; + if (GetUserNameW(usernameBuf, &bufSize)) { + userName = QString::fromWCharArray(usernameBuf); + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && IsUserAdmin()) { + // Special case : If the user is a member of Administrators group, all files + // created by the current user are owned by the Administrators group. + LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; + DWORD dwLevel = 0; + DWORD dwFlags = LG_INCLUDE_INDIRECT ; + DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; + DWORD dwEntriesRead = 0; + DWORD dwTotalEntries = 0; + NET_API_STATUS nStatus; + nStatus = NetUserGetLocalGroups(0, usernameBuf, dwLevel, dwFlags, (LPBYTE *) &pBuf, + dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); + // Check if the current user is a member of Administrators group + if (nStatus == NERR_Success && pBuf){ + for (int i = 0; i < dwEntriesRead; i++) { + QString groupName = QString::fromWCharArray(pBuf[i].lgrui0_name); + if (!groupName.compare(QLatin1String("Administrators"))) + userName = groupName; + } + } + if (pBuf != NULL) + NetApiBufferFree(pBuf); + } + } + extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; + qt_ntfs_permission_lookup = 1; +#endif + if (userName.isEmpty()) + QSKIP("Can't retrieve the user name", SkipAll); + QString fileName("ownertest.txt"); + QVERIFY(!QFile::exists(fileName) || QFile::remove(fileName)); + { + QFile testFile(fileName); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); + QByteArray testData("testfile"); + QVERIFY(testFile.write(testData) != -1); + } + QFileInfo fi(fileName); + QVERIFY(fi.exists()); + QCOMPARE(fi.owner(), userName); + + QFile::remove(fileName); +#if defined(Q_OS_WIN) + qt_ntfs_permission_lookup = 0; +#endif +} +#endif + +void tst_QFileInfo::group() +{ + QString expected; +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) + struct group *gr; + gid_t gid = getegid(); + gr = getgrgid(gid); + expected = QString::fromLocal8Bit(gr->gr_name); +#endif + + QString fileName("ownertest.txt"); + if (QFile::exists(fileName)) + QFile::remove(fileName); + QFile testFile(fileName); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); + QByteArray testData("testfile"); + QVERIFY(testFile.write(testData) != -1); + testFile.close(); + QFileInfo fi(fileName); + QVERIFY(fi.exists()); + + QCOMPARE(fi.group(), expected); +} + +void tst_QFileInfo::invalidState() +{ + // Shouldn't crash; + + { + QFileInfo info; + QCOMPARE(info.size(), qint64(0)); + QVERIFY(!info.exists()); + + info.setCaching(false); + + info.created(); + info.lastRead(); + info.lastModified(); + } + + { + QFileInfo info(""); + QCOMPARE(info.size(), qint64(0)); + QVERIFY(!info.exists()); + + info.setCaching(false); + + info.created(); + info.lastRead(); + info.lastModified(); + } + + { + QFileInfo info("file-doesn't-really-exist.txt"); + QCOMPARE(info.size(), qint64(0)); + QVERIFY(!info.exists()); + + info.setCaching(false); + + info.created(); + info.lastRead(); + info.lastModified(); + } + + QVERIFY(true); +} + +QTEST_MAIN(tst_QFileInfo) +#include "tst_qfileinfo.moc" diff --git a/tests/auto/corelib/io/qfilesystementry/qfilesystementry.pro b/tests/auto/corelib/io/qfilesystementry/qfilesystementry.pro new file mode 100644 index 0000000000..992c90cfcc --- /dev/null +++ b/tests/auto/corelib/io/qfilesystementry/qfilesystementry.pro @@ -0,0 +1,8 @@ +load(qttest_p4) + +SOURCES += tst_qfilesystementry.cpp \ + $${QT.core.sources}/io/qfilesystementry.cpp +HEADERS += $${QT.core.sources}/io/qfilesystementry_p.h +QT = core core-private + +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qfilesystementry/tst_qfilesystementry.cpp b/tests/auto/corelib/io/qfilesystementry/tst_qfilesystementry.cpp new file mode 100644 index 0000000000..016bcbfe8a --- /dev/null +++ b/tests/auto/corelib/io/qfilesystementry/tst_qfilesystementry.cpp @@ -0,0 +1,387 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> + +#include <QtCore/private/qfilesystementry_p.h> + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +# define WIN_STUFF +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFileSystemEntry : public QObject +{ + Q_OBJECT + +private slots: + void getSetCheck_data(); + void getSetCheck(); + void suffix_data(); + void suffix(); + void completeSuffix_data(); + void completeSuffix(); + void baseName_data(); + void baseName(); + void completeBaseName_data(); + void completeBaseName(); +#if defined(WIN_STUFF) + void absoluteOrRelative_data(); + void absoluteOrRelative(); +#endif +}; + +#if defined(WIN_STUFF) +void tst_QFileSystemEntry::getSetCheck_data() +{ + QTest::addColumn<QString>("nativeFilePath"); + QTest::addColumn<QString>("internalnativeFilePath"); + QTest::addColumn<QString>("filepath"); + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("baseName"); + QTest::addColumn<QString>("completeBasename"); + QTest::addColumn<QString>("suffix"); + QTest::addColumn<QString>("completeSuffix"); + QTest::addColumn<bool>("absolute"); + QTest::addColumn<bool>("relative"); + + QString absPrefix = QLatin1String("\\\\?\\"); + QString relPrefix = absPrefix + + QDir::toNativeSeparators(QDir::currentPath()) + + QLatin1String("\\"); + + QTest::newRow("simple") + << QString("A:\\home\\qt\\in\\a\\dir.tar.gz") + << absPrefix + QString("A:\\home\\qt\\in\\a\\dir.tar.gz") + << "A:/home/qt/in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << true << false; + + QTest::newRow("relative") + << QString("in\\a\\dir.tar.gz") + << relPrefix + QString("in\\a\\dir.tar.gz") + << "in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << false <<true; + + QTest::newRow("noSuffix") + << QString("myDir\\myfile") + << relPrefix + QString("myDir\\myfile") + << "myDir/myfile" << "myfile" << "myfile" << "myfile" << "" << "" << false <<true; + + QTest::newRow("noLongSuffix") + << QString("myDir\\myfile.txt") + << relPrefix + QString("myDir\\myfile.txt") + << "myDir/myfile.txt" << "myfile.txt" << "myfile" << "myfile" << "txt" << "txt" << false << true; + + QTest::newRow("endingSlash") + << QString("myDir\\myfile.bla\\") + << relPrefix + QString("myDir\\myfile.bla\\") + << "myDir/myfile.bla/" << "" << "" << "" << "" << "" << false << true; + + QTest::newRow("absolutePath") + << QString("A:dir\\without\\leading\\backslash.bat") + << absPrefix + QString("A:\\dir\\without\\leading\\backslash.bat") + << "A:dir/without/leading/backslash.bat" << "backslash.bat" << "backslash" << "backslash" << "bat" << "bat" << false << false; +} + +void tst_QFileSystemEntry::getSetCheck() +{ + QFETCH(QString, nativeFilePath); + QFETCH(QString, internalnativeFilePath); + QFETCH(QString, filepath); + QFETCH(QString, filename); + QFETCH(QString, baseName); + QFETCH(QString, completeBasename); + QFETCH(QString, suffix); + QFETCH(QString, completeSuffix); + QFETCH(bool, absolute); + QFETCH(bool, relative); + + QFileSystemEntry entry1(filepath); + QCOMPARE(entry1.filePath(), filepath); + QCOMPARE(entry1.nativeFilePath().toLower(), internalnativeFilePath.toLower()); + QCOMPARE(entry1.fileName(), filename); + QCOMPARE(entry1.suffix(), suffix); + QCOMPARE(entry1.completeSuffix(), completeSuffix); + QCOMPARE(entry1.isAbsolute(), absolute); + QCOMPARE(entry1.isRelative(), relative); + QCOMPARE(entry1.baseName(), baseName); + QCOMPARE(entry1.completeBaseName(), completeBasename); + + QFileSystemEntry entry2(nativeFilePath, QFileSystemEntry::FromNativePath()); + QCOMPARE(entry2.suffix(), suffix); + QCOMPARE(entry2.completeSuffix(), completeSuffix); + QCOMPARE(entry2.isAbsolute(), absolute); + QCOMPARE(entry2.isRelative(), relative); + QCOMPARE(entry2.filePath(), filepath); + // Since this entry was created using the native path, + // the object shouldnot change nativeFilePath. + QCOMPARE(entry2.nativeFilePath(), nativeFilePath); + QCOMPARE(entry2.fileName(), filename); + QCOMPARE(entry2.baseName(), baseName); + QCOMPARE(entry2.completeBaseName(), completeBasename); +} + +#else + +void tst_QFileSystemEntry::getSetCheck_data() +{ + QTest::addColumn<QByteArray>("nativeFilePath"); + QTest::addColumn<QString>("filepath"); + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("basename"); + QTest::addColumn<QString>("completeBasename"); + QTest::addColumn<QString>("suffix"); + QTest::addColumn<QString>("completeSuffix"); + QTest::addColumn<bool>("absolute"); + + QTest::newRow("simple") + << QByteArray("/home/qt/in/a/dir.tar.gz") + << "/home/qt/in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << true; + QTest::newRow("relative") + << QByteArray("in/a/dir.tar.gz") + << "in/a/dir.tar.gz" + << "dir.tar.gz" << "dir" << "dir.tar" << "gz" << "tar.gz" << false; + + QTest::newRow("noSuffix") + << QByteArray("myDir/myfile") + << "myDir/myfile" << "myfile" << "myfile" << "myfile" << "" << "" << false; + + QTest::newRow("noLongSuffix") + << QByteArray("myDir/myfile.txt") + << "myDir/myfile.txt" << "myfile.txt" << "myfile" << "myfile" << "txt" << "txt" << false; + + QTest::newRow("endingSlash") + << QByteArray("myDir/myfile.bla/") + << "myDir/myfile.bla/" << "" << "" << "" << "" << "" << false; + + QTest::newRow("relativePath") + << QByteArray("A:dir/without/leading/backslash.bat") + << "A:dir/without/leading/backslash.bat" << "backslash.bat" << "backslash" << "backslash" << "bat" << "bat" << false; +} + +void tst_QFileSystemEntry::getSetCheck() +{ + QFETCH(QByteArray, nativeFilePath); + QFETCH(QString, filepath); + QFETCH(QString, filename); + QFETCH(QString, basename); + QFETCH(QString, completeBasename); + QFETCH(QString, suffix); + QFETCH(QString, completeSuffix); + QFETCH(bool, absolute); + + QFileSystemEntry entry1(filepath); + QCOMPARE(entry1.filePath(), filepath); + QCOMPARE(entry1.nativeFilePath(), nativeFilePath); + QCOMPARE(entry1.fileName(), filename); + QCOMPARE(entry1.suffix(), suffix); + QCOMPARE(entry1.completeSuffix(), completeSuffix); + QCOMPARE(entry1.isAbsolute(), absolute); + QCOMPARE(entry1.isRelative(), !absolute); + QCOMPARE(entry1.baseName(), basename); + QCOMPARE(entry1.completeBaseName(), completeBasename); + + QFileSystemEntry entry2(nativeFilePath, QFileSystemEntry::FromNativePath()); + QCOMPARE(entry2.suffix(), suffix); + QCOMPARE(entry2.completeSuffix(), completeSuffix); + QCOMPARE(entry2.isAbsolute(), absolute); + QCOMPARE(entry2.isRelative(), !absolute); + QCOMPARE(entry2.filePath(), filepath); + QCOMPARE(entry2.nativeFilePath(), nativeFilePath); + QCOMPARE(entry2.fileName(), filename); + QCOMPARE(entry2.baseName(), basename); + QCOMPARE(entry2.completeBaseName(), completeBasename); +} +#endif + +void tst_QFileSystemEntry::suffix_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("noextension0") << "file" << ""; + QTest::newRow("noextension1") << "/path/to/file" << ""; + QTest::newRow("data0") << "file.tar" << "tar"; + QTest::newRow("data1") << "file.tar.gz" << "gz"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "gz"; + QTest::newRow("data3") << "/path/file.tar" << "tar"; + QTest::newRow("hidden1") << ".ext1" << "ext1"; + QTest::newRow("hidden1") << ".ext" << "ext"; + QTest::newRow("hidden1") << ".ex" << "ex"; + QTest::newRow("hidden1") << ".e" << "e"; + QTest::newRow("hidden2") << ".ext1.ext2" << "ext2"; + QTest::newRow("hidden2") << ".ext.ext2" << "ext2"; + QTest::newRow("hidden2") << ".ex.ext2" << "ext2"; + QTest::newRow("hidden2") << ".e.ext2" << "ext2"; + QTest::newRow("hidden2") << "..ext2" << "ext2"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << "ext2"; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << "ext2"; +} + +void tst_QFileSystemEntry::suffix() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fe(file); + QCOMPARE(fe.suffix(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.suffix(), expected); +} + +void tst_QFileSystemEntry::completeSuffix_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("noextension0") << "file" << ""; + QTest::newRow("noextension1") << "/path/to/file" << ""; + QTest::newRow("data0") << "file.tar" << "tar"; + QTest::newRow("data1") << "file.tar.gz" << "tar.gz"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "tar.gz"; + QTest::newRow("data3") << "/path/file.tar" << "tar"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << ".ext2"; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << "file..ext2"; +} + +void tst_QFileSystemEntry::completeSuffix() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fi(file); + QCOMPARE(fi.completeSuffix(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.completeSuffix(), expected); +} + +void tst_QFileSystemEntry::baseName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("data0") << "file.tar" << "file"; + QTest::newRow("data1") << "file.tar.gz" << "file"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "file"; + QTest::newRow("data3") << "/path/file.tar" << "file"; + QTest::newRow("data4") << "/path/file" << "file"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << "file"; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << ""; +} + +void tst_QFileSystemEntry::baseName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fi(file); + QCOMPARE(fi.baseName(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.baseName(), expected); +} + +void tst_QFileSystemEntry::completeBaseName_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("data0") << "file.tar" << "file"; + QTest::newRow("data1") << "file.tar.gz" << "file.tar"; + QTest::newRow("data2") << "/path/file/file.tar.gz" << "file.tar"; + QTest::newRow("data3") << "/path/file.tar" << "file"; + QTest::newRow("data4") << "/path/file" << "file"; + QTest::newRow("dots") << "/path/file.with.dots/file..ext2" << "file."; + QTest::newRow("dots2") << "/path/file.with.dots/.file..ext2" << ".file."; +} + +void tst_QFileSystemEntry::completeBaseName() +{ + QFETCH(QString, file); + QFETCH(QString, expected); + + QFileSystemEntry fi(file); + QCOMPARE(fi.completeBaseName(), expected); + + QFileSystemEntry fi2(file); + // first resolve the last slash + (void) fi2.path(); + QCOMPARE(fi2.completeBaseName(), expected); +} + +#if defined(WIN_STUFF) +void tst_QFileSystemEntry::absoluteOrRelative_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("isAbsolute"); + QTest::addColumn<bool>("isRelative"); + + QTest::newRow("data0") << "file.tar" << false << true; + QTest::newRow("data1") << "/path/file/file.tar.gz" << false << false; + QTest::newRow("data1") << "C:path/file/file.tar.gz" << false << false; + QTest::newRow("data3") << "C:/path/file" << true << false; + QTest::newRow("data3") << "//machine/share" << true << false; +} + +void tst_QFileSystemEntry::absoluteOrRelative() +{ + QFETCH(QString, path); + QFETCH(bool, isAbsolute); + QFETCH(bool, isRelative); + + QFileSystemEntry fi(path); + QCOMPARE(fi.isAbsolute(), isAbsolute); + QCOMPARE(fi.isRelative(), isRelative); +} +#endif + +QTEST_MAIN(tst_QFileSystemEntry) +#include <tst_qfilesystementry.moc> diff --git a/tests/auto/corelib/io/qfilesystemwatcher/.gitignore b/tests/auto/corelib/io/qfilesystemwatcher/.gitignore new file mode 100644 index 0000000000..19c6c08e03 --- /dev/null +++ b/tests/auto/corelib/io/qfilesystemwatcher/.gitignore @@ -0,0 +1 @@ +tst_qfilesystemwatcher diff --git a/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro b/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro new file mode 100644 index 0000000000..d3549b2f05 --- /dev/null +++ b/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qfilesystemwatcher.cpp +QT = core + +CONFIG += parallel_test +CONFIG += insignificant_test diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp new file mode 100644 index 0000000000..9d46a8d863 --- /dev/null +++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -0,0 +1,574 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> + +#include <QCoreApplication> + +#include <QFileSystemWatcher> + +#ifdef Q_OS_LINUX +# ifdef QT_NO_INOTIFY +# include <linux/version.h> +# else +# include <sys/inotify.h> +# endif +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFileSystemWatcher : public QObject +{ + Q_OBJECT + +public: + tst_QFileSystemWatcher(); + +private slots: + void basicTest_data(); + void basicTest(); + + void watchDirectory_data() { basicTest_data(); } + void watchDirectory(); + + void addPath(); + void removePath(); + void addPaths(); + void removePaths(); + + void watchFileAndItsDirectory_data() { basicTest_data(); } + void watchFileAndItsDirectory(); + + void nonExistingFile(); + + void removeFileAndUnWatch(); + + void cleanup(); + + void QTBUG15255_deadlock(); +private: + QStringList do_force_engines; + bool do_force_native; +}; + +tst_QFileSystemWatcher::tst_QFileSystemWatcher() + : do_force_native(false) +{ +#ifdef Q_OS_LINUX + // the inotify implementation in the kernel is known to be buggy in certain versions of the linux kernel + do_force_engines << "native"; + do_force_engines << "dnotify"; + +#ifdef QT_NO_INOTIFY + if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) + do_force_engines << "inotify"; +#else + if (inotify_init() != -1) + do_force_engines << "inotify"; +#endif +#elif defined(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_FREEBSD) || defined(Q_OS_SYMBIAN) + // we have native engines for win32, macosx and freebsd + do_force_engines << "native"; +#endif +} + +void tst_QFileSystemWatcher::basicTest_data() +{ + QTest::addColumn<QString>("backend"); + foreach(QString engine, do_force_engines) + QTest::newRow(engine.toLatin1().constData()) << engine; + QTest::newRow("poller") << "poller"; +} + +void tst_QFileSystemWatcher::basicTest() +{ + QFETCH(QString, backend); + qDebug() << "Testing" << backend << "engine"; + + // create test file + QFile testFile("testfile.txt"); + testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner); + testFile.remove(); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); + testFile.write(QByteArray("hello")); + testFile.close(); + + // set some file permissions + testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner); + + // create watcher, forcing it to use a specific backend + QFileSystemWatcher watcher; + watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); + watcher.removePath(testFile.fileName()); + watcher.addPath(testFile.fileName()); + + QSignalSpy changedSpy(&watcher, SIGNAL(fileChanged(const QString &))); + QEventLoop eventLoop; + QTimer timer; + connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); + + // modify the file, should get a signal from the watcher + + // resolution of the modification time is system dependent, but it's at most 1 second when using + // the polling engine. I've heard rumors that FAT32 has a 2 second resolution. So, we have to + // wait a bit before we can modify the file (hrmph)... +#ifndef Q_OS_WINCE + QTest::qWait(2000); +#else + // WinCE is always a little bit slower. Give it a little bit more time + QTest::qWait(5000); +#endif + + testFile.open(QIODevice::WriteOnly | QIODevice::Append); + testFile.write(QByteArray("world")); + testFile.close(); + + // qDebug() << "waiting max 5 seconds for notification for file modification to trigger(1)"; + timer.start(5000); + eventLoop.exec(); + + QCOMPARE(changedSpy.count(), 1); + QCOMPARE(changedSpy.at(0).count(), 1); + + QString fileName = changedSpy.at(0).at(0).toString(); + QCOMPARE(fileName, testFile.fileName()); + + changedSpy.clear(); + + // remove the watch and modify the file, should not get a signal from the watcher + watcher.removePath(testFile.fileName()); + testFile.open(QIODevice::WriteOnly | QIODevice::Truncate); + testFile.write(QByteArray("hello universe!")); + testFile.close(); + + // qDebug() << "waiting max 5 seconds for notification for file modification to trigger (2)"; + timer.start(5000); + eventLoop.exec(); + + QCOMPARE(changedSpy.count(), 0); + + // readd the file watch with a relative path + watcher.addPath(testFile.fileName().prepend("./")); + testFile.open(QIODevice::WriteOnly | QIODevice::Truncate); + testFile.write(QByteArray("hello multiverse!")); + testFile.close(); + + timer.start(5000); + eventLoop.exec(); + + QVERIFY(changedSpy.count() > 0); + + watcher.removePath(testFile.fileName().prepend("./")); + + changedSpy.clear(); + + // readd the file watch + watcher.addPath(testFile.fileName()); + + // change the permissions, should get a signal from the watcher + testFile.setPermissions(QFile::ReadOwner); + + // qDebug() << "waiting max 5 seconds for notification for file permission modification to trigger(1)"; + timer.start(5000); + eventLoop.exec(); + + QCOMPARE(changedSpy.count(), 1); + QCOMPARE(changedSpy.at(0).count(), 1); + + fileName = changedSpy.at(0).at(0).toString(); + QCOMPARE(fileName, testFile.fileName()); + + changedSpy.clear(); + + // remove the watch and modify file permissions, should not get a signal from the watcher + watcher.removePath(testFile.fileName()); + testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOther); + + // qDebug() << "waiting max 5 seconds for notification for file modification to trigger (2)"; + timer.start(5000); + eventLoop.exec(); + + QCOMPARE(changedSpy.count(), 0); + + // readd the file watch + watcher.addPath(testFile.fileName()); + + // remove the file, should get a signal from the watcher + QVERIFY(testFile.remove()); + + // qDebug() << "waiting max 5 seconds for notification for file removal to trigger"; + timer.start(5000); + eventLoop.exec(); + + QVERIFY(changedSpy.count() == 1 || changedSpy.count() == 2); // removing a file on some filesystems seems to deliver 2 notifications + QCOMPARE(changedSpy.at(0).count(), 1); + + fileName = changedSpy.at(0).at(0).toString(); + QCOMPARE(fileName, testFile.fileName()); + + changedSpy.clear(); + + // recreate the file, we should not get any notification + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); + testFile.write(QByteArray("hello")); + testFile.close(); + + // qDebug() << "waiting max 5 seconds for notification for file recreation to trigger"; + timer.start(5000); + eventLoop.exec(); + + QCOMPARE(changedSpy.count(), 0); + + QVERIFY(testFile.remove()); +} + +void tst_QFileSystemWatcher::watchDirectory() +{ + QFETCH(QString, backend); + qDebug() << "Testing" << backend << "engine"; + + QDir().mkdir("testDir"); + QDir testDir("testDir"); + + QString testFileName = testDir.filePath("testFile.txt"); + QFile::remove(testFileName); + + QFileSystemWatcher watcher; + watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); + watcher.addPath(testDir.dirName()); + + QSignalSpy changedSpy(&watcher, SIGNAL(directoryChanged(const QString &))); + QEventLoop eventLoop; + QTimer timer; + connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); + + // resolution of the modification time is system dependent, but it's at most 1 second when using + // the polling engine. From what I know, FAT32 has a 2 second resolution. So we have to + // wait before modifying the directory... + QTest::qWait(2000); + QFile testFile(testFileName); + QString fileName; + + // remove the watch, should not get notification of a new file + watcher.removePath(testDir.dirName()); + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); + testFile.close(); + + // qDebug() << "waiting max 5 seconds for notification for file recreationg to trigger"; + timer.start(5000); + eventLoop.exec(); + + QCOMPARE(changedSpy.count(), 0); + + watcher.addPath(testDir.dirName()); + + // remove the file again, should get a signal from the watcher + QVERIFY(testFile.remove()); + + timer.start(5000); + eventLoop.exec(); + + // remove the directory, should get a signal from the watcher + QVERIFY(QDir().rmdir("testDir")); + + // qDebug() << "waiting max 5 seconds for notification for directory removal to trigger"; + timer.start(5000); + eventLoop.exec(); + +#ifdef Q_OS_WINCE + QEXPECT_FAIL("poller", "Directory does not get updated on file removal(See #137910)", Abort); +#endif + QCOMPARE(changedSpy.count(), 2); + QCOMPARE(changedSpy.at(0).count(), 1); + QCOMPARE(changedSpy.at(1).count(), 1); + + fileName = changedSpy.at(0).at(0).toString(); + QCOMPARE(fileName, testDir.dirName()); + fileName = changedSpy.at(1).at(0).toString(); + QCOMPARE(fileName, testDir.dirName()); + + changedSpy.clear(); + + // recreate the file, we should not get any notification + if (!QDir().mkdir("testDir")) + QSKIP("Failed to recreate directory, skipping final test.", SkipSingle); + + // qDebug() << "waiting max 5 seconds for notification for dir recreation to trigger"; + timer.start(5000); + eventLoop.exec(); + + QCOMPARE(changedSpy.count(), 0); + + QVERIFY(QDir().rmdir("testDir")); +} + +void tst_QFileSystemWatcher::addPath() +{ + QFileSystemWatcher watcher; + QString home = QDir::homePath(); + watcher.addPath(home); + QCOMPARE(watcher.directories().count(), 1); + QCOMPARE(watcher.directories().first(), home); + watcher.addPath(home); + QCOMPARE(watcher.directories().count(), 1); + + // With empty string + QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::addPath: path is empty"); + watcher.addPath(QString()); +} + +void tst_QFileSystemWatcher::removePath() +{ + QFileSystemWatcher watcher; + QString home = QDir::homePath(); + watcher.addPath(home); + watcher.removePath(home); + QCOMPARE(watcher.directories().count(), 0); + watcher.removePath(home); + QCOMPARE(watcher.directories().count(), 0); + + // With empty string + QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::removePath: path is empty"); + watcher.removePath(QString()); +} + +void tst_QFileSystemWatcher::addPaths() +{ + QFileSystemWatcher watcher; + QStringList paths; + paths << QDir::homePath() << QDir::currentPath(); + watcher.addPaths(paths); + QCOMPARE(watcher.directories().count(), 2); + + // With empty list + paths.clear(); + QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::addPaths: list is empty"); + watcher.addPaths(paths); +} + +void tst_QFileSystemWatcher::removePaths() +{ + QFileSystemWatcher watcher; + QStringList paths; + paths << QDir::homePath() << QDir::currentPath(); + watcher.addPaths(paths); + QCOMPARE(watcher.directories().count(), 2); + watcher.removePaths(paths); + QCOMPARE(watcher.directories().count(), 0); + + //With empty list + paths.clear(); + QTest::ignoreMessage(QtWarningMsg, "QFileSystemWatcher::removePaths: list is empty"); + watcher.removePaths(paths); +} + +#if 0 +class SignalTest : public QObject { + Q_OBJECT + public slots: + void fileSlot(const QString &file) { qDebug() << "file " << file;} + void dirSlot(const QString &dir) { qDebug() << "dir" << dir;} +}; +#endif + +void tst_QFileSystemWatcher::watchFileAndItsDirectory() +{ + QFETCH(QString, backend); + QDir().mkdir("testDir"); + QDir testDir("testDir"); + + QString testFileName = testDir.filePath("testFile.txt"); + QString secondFileName = testDir.filePath("testFile2.txt"); + QFile::remove(secondFileName); + + QFile testFile(testFileName); + testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner); + testFile.remove(); + + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); + testFile.write(QByteArray("hello")); + testFile.close(); + + QFileSystemWatcher watcher; + watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_") + backend); + + watcher.addPath(testDir.dirName()); + watcher.addPath(testFileName); + + /* + SignalTest signalTest; + QObject::connect(&watcher, SIGNAL(fileChanged(const QString &)), &signalTest, SLOT(fileSlot(const QString &))); + QObject::connect(&watcher, SIGNAL(directoryChanged(const QString &)), &signalTest, SLOT(dirSlot(const QString &))); + */ + + QSignalSpy fileChangedSpy(&watcher, SIGNAL(fileChanged(const QString &))); + QSignalSpy dirChangedSpy(&watcher, SIGNAL(directoryChanged(const QString &))); + QEventLoop eventLoop; + QTimer timer; + connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); + + // resolution of the modification time is system dependent, but it's at most 1 second when using + // the polling engine. From what I know, FAT32 has a 2 second resolution. So we have to + // wait before modifying the directory... + QTest::qWait(2000); + + QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); + testFile.write(QByteArray("hello again")); + testFile.close(); + + timer.start(3000); + eventLoop.exec(); + QVERIFY(fileChangedSpy.count() > 0); + //according to Qt 4 documentation: + //void QFileSystemWatcher::directoryChanged ( const QString & path ) [signal] + //This signal is emitted when the directory at a specified path, is modified + //(e.g., when a file is added, -->modified<-- or deleted) or removed from disk. + //Note that if there are several changes during a short period of time, some + //of the changes might not emit this signal. However, the last change in the + //sequence of changes will always generate this signal. + //Symbian behaves as documented (and can't be filtered), but the other platforms don't + //so test should not assert this + QVERIFY(dirChangedSpy.count() < 2); + + if (backend == "dnotify") + QSKIP("dnotify is broken, skipping the rest of the test.", SkipSingle); + + fileChangedSpy.clear(); + dirChangedSpy.clear(); + QFile secondFile(secondFileName); + secondFile.open(QIODevice::WriteOnly | QIODevice::Truncate); + secondFile.write("Foo"); + secondFile.close(); + + timer.start(3000); + eventLoop.exec(); + QCOMPARE(fileChangedSpy.count(), 0); +#ifdef Q_OS_WINCE + QEXPECT_FAIL("poller", "Directory does not get updated on file removal(See #137910)", Abort); +#endif + QCOMPARE(dirChangedSpy.count(), 1); + + dirChangedSpy.clear(); + + QFile::remove(testFileName); + + timer.start(3000); + eventLoop.exec(); + QVERIFY(fileChangedSpy.count() > 0); + QCOMPARE(dirChangedSpy.count(), 1); + + fileChangedSpy.clear(); + dirChangedSpy.clear(); + + watcher.removePath(testFileName); + QFile::remove(secondFileName); + + timer.start(3000); + eventLoop.exec(); + QCOMPARE(fileChangedSpy.count(), 0); + // polling watcher has generated separate events for content and time change + // on Symbian emulator, so allow possibility of 2 events + QVERIFY(dirChangedSpy.count() == 1 || dirChangedSpy.count() == 2); + + QVERIFY(QDir().rmdir("testDir")); +} + +void tst_QFileSystemWatcher::cleanup() +{ + QDir testDir("testDir"); + QString testFileName = testDir.filePath("testFile.txt"); + QString secondFileName = testDir.filePath("testFile2.txt"); + QFile::remove(testFileName); + QFile::remove(secondFileName); + QDir().rmdir("testDir"); +} + +void tst_QFileSystemWatcher::nonExistingFile() +{ + // Don't crash... + QFileSystemWatcher watcher; + watcher.addPath("file_that_does_not_exist.txt"); + QVERIFY(true); +} + +void tst_QFileSystemWatcher::removeFileAndUnWatch() +{ + static const char * const filename = "foo.txt"; + QFileSystemWatcher watcher; + + { + QFile testFile(filename); + testFile.open(QIODevice::WriteOnly); + testFile.close(); + } + watcher.addPath(filename); + + QFile::remove(filename); + watcher.removePath(filename); + + { + QFile testFile(filename); + testFile.open(QIODevice::WriteOnly); + testFile.close(); + } + watcher.addPath(filename); +} + +class SomeSingleton : public QObject +{ +public: + SomeSingleton() : mFsWatcher(new QFileSystemWatcher(this)) { mFsWatcher->addPath(QLatin1String("/usr/lib"));} + void bla() const {} + QFileSystemWatcher* mFsWatcher; +}; + +Q_GLOBAL_STATIC(SomeSingleton, someSingleton) + +void tst_QFileSystemWatcher::QTBUG15255_deadlock() +{ + someSingleton()->bla(); + //the test must still finish + QTest::qWait(30); +} + + +QTEST_MAIN(tst_QFileSystemWatcher) +#include "tst_qfilesystemwatcher.moc" diff --git a/tests/auto/corelib/io/qiodevice/.gitignore b/tests/auto/corelib/io/qiodevice/.gitignore new file mode 100644 index 0000000000..e503843519 --- /dev/null +++ b/tests/auto/corelib/io/qiodevice/.gitignore @@ -0,0 +1,2 @@ +tst_qiodevice +peektestfile diff --git a/tests/auto/corelib/io/qiodevice/qiodevice.pro b/tests/auto/corelib/io/qiodevice/qiodevice.pro new file mode 100644 index 0000000000..08996e8cd4 --- /dev/null +++ b/tests/auto/corelib/io/qiodevice/qiodevice.pro @@ -0,0 +1,23 @@ +load(qttest_p4) +SOURCES += tst_qiodevice.cpp + +QT = core network + +wince*: { + addFiles.files = tst_qiodevice.cpp + addFiles.path = . + DEPLOYMENT += addFiles + DEFINES += SRCDIR=\\\"\\\" + !wince50standard-x86-msvc2005: DEFINES += WINCE_EMULATOR_TEST=1 +} else:symbian { + # SRCDIR defined in code in symbian + addFiles.files = tst_qiodevice.cpp + addFiles.path = . + DEPLOYMENT += addFiles + TARGET.CAPABILITY = NetworkServices +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} +MOC_DIR=tmp + + diff --git a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp new file mode 100644 index 0000000000..425b3b6bd1 --- /dev/null +++ b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp @@ -0,0 +1,611 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore/QtCore> +#include <QtNetwork/QtNetwork> +#include <QtTest/QtTest> + +#include "../../../network-settings.h" + +//TESTED_CLASS= +//TESTED_FILES= + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "" +#endif + +class tst_QIODevice : public QObject +{ + Q_OBJECT + +public: + tst_QIODevice(); + virtual ~tst_QIODevice(); + + +public slots: + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void constructing_QTcpSocket(); + void constructing_QFile(); + void read_QByteArray(); + void unget(); + void peek(); + void peekAndRead(); + + void readLine_data(); + void readLine(); + + void readLine2_data(); + void readLine2(); + + void peekBug(); +}; + +// Testing get/set functions +void tst_QIODevice::getSetCheck() +{ + // OpenMode QIODevice::openMode() + // void QIODevice::setOpenMode(OpenMode) + class MyIODevice : public QIODevice { + public: + void setOpenMode(OpenMode openMode) { QIODevice::setOpenMode(openMode); } + }; + QTcpSocket var1; + MyIODevice *obj1 = reinterpret_cast<MyIODevice*>(&var1); + obj1->setOpenMode(QIODevice::OpenMode(QIODevice::NotOpen)); + QCOMPARE(QIODevice::OpenMode(QIODevice::NotOpen), obj1->openMode()); + obj1->setOpenMode(QIODevice::OpenMode(QIODevice::ReadWrite)); + QCOMPARE(QIODevice::OpenMode(QIODevice::ReadWrite), obj1->openMode()); +} + +tst_QIODevice::tst_QIODevice() +{ + Q_SET_DEFAULT_IAP +} + +tst_QIODevice::~tst_QIODevice() +{ +} + +void tst_QIODevice::init() +{ +} + +void tst_QIODevice::cleanup() +{ +} + +//---------------------------------------------------------------------------------- +void tst_QIODevice::constructing_QTcpSocket() +{ +#if defined(Q_OS_WINCE) && defined(WINCE_EMULATOR_TEST) + QSKIP("Networking tests in a WinCE emulator are unstable", SkipAll); +#endif + QTcpSocket socket; + QIODevice *device = &socket; + + QVERIFY(!device->isOpen()); + + socket.connectToHost(QtNetworkSettings::serverName(), 143); + QVERIFY(socket.waitForConnected(30000)); + QVERIFY(device->isOpen()); + + while (!device->canReadLine()) + QVERIFY(device->waitForReadyRead(30000)); + + char buf[1024]; + memset(buf, 0, sizeof(buf)); + qlonglong lineLength = device->readLine(buf, sizeof(buf)); + QVERIFY(lineLength > 0); + QCOMPARE(socket.pos(), qlonglong(0)); + + socket.close(); + socket.connectToHost(QtNetworkSettings::serverName(), 143); + QVERIFY(socket.waitForConnected(30000)); + QVERIFY(device->isOpen()); + + while (!device->canReadLine()) + QVERIFY(device->waitForReadyRead(30000)); + + char buf2[1024]; + memset(buf2, 0, sizeof(buf2)); + QCOMPARE(socket.readLine(buf2, sizeof(buf2)), lineLength); + + char *c1 = buf; + char *c2 = buf2; + while (*c1 && *c2) { + QCOMPARE(*c1, *c2); + ++c1; + ++c2; + } + QCOMPARE(*c1, *c2); +} + +//---------------------------------------------------------------------------------- +void tst_QIODevice::constructing_QFile() +{ + QFile file; + QIODevice *device = &file; + + QVERIFY(!device->isOpen()); + + file.setFileName(SRCDIR "tst_qiodevice.cpp"); + QVERIFY(file.open(QFile::ReadOnly)); + QVERIFY(device->isOpen()); + QCOMPARE((int) device->openMode(), (int) QFile::ReadOnly); + + char buf[1024]; + memset(buf, 0, sizeof(buf)); + qlonglong lineLength = device->readLine(buf, sizeof(buf)); + QVERIFY(lineLength > 0); + QCOMPARE(file.pos(), lineLength); + + file.seek(0); + char buf2[1024]; + memset(buf2, 0, sizeof(buf2)); + QCOMPARE(file.readLine(buf2, sizeof(buf2)), lineLength); + + char *c1 = buf; + char *c2 = buf2; + while (*c1 && *c2) { + QCOMPARE(*c1, *c2); + ++c1; + ++c2; + } + QCOMPARE(*c1, *c2); +} + + +void tst_QIODevice::read_QByteArray() +{ + QFile f(SRCDIR "tst_qiodevice.cpp"); + f.open(QIODevice::ReadOnly); + + QByteArray b = f.read(10); + QCOMPARE(b.length(), 10); + + b = f.read(256); + QCOMPARE(b.length(), 256); + + b = f.read(0); + QCOMPARE(b.length(), 0); +} + +//-------------------------------------------------------------------- +void tst_QIODevice::unget() +{ +#if defined(Q_OS_WINCE) && defined(WINCE_EMULATOR_TEST) + QSKIP("Networking tests in a WinCE emulator are unstable", SkipAll); +#endif + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + buffer.write("ZXCV"); + buffer.seek(0); + QCOMPARE(buffer.read(4), QByteArray("ZXCV")); + QCOMPARE(buffer.pos(), qint64(4)); + + buffer.ungetChar('a'); + buffer.ungetChar('b'); + buffer.ungetChar('c'); + buffer.ungetChar('d'); + + QCOMPARE(buffer.pos(), qint64(0)); + + char buf[6]; + QCOMPARE(buffer.readLine(buf, 5), qint64(4)); + QCOMPARE(buffer.pos(), qint64(4)); + QCOMPARE(static_cast<const char*>(buf), "dcba"); + + buffer.ungetChar('a'); + buffer.ungetChar('b'); + buffer.ungetChar('c'); + buffer.ungetChar('d'); + + QCOMPARE(buffer.pos(), qint64(0)); + + for (int i = 0; i < 5; ++i) { + buf[0] = '@'; + buf[1] = '@'; + QTest::ignoreMessage(QtWarningMsg, + "QIODevice::readLine: Called with maxSize < 2"); + QCOMPARE(buffer.readLine(buf, 1), qint64(-1)); + QCOMPARE(buffer.readLine(buf, 2), qint64(i < 4 ? 1 : -1)); + switch (i) { + case 0: QCOMPARE(buf[0], 'd'); break; + case 1: QCOMPARE(buf[0], 'c'); break; + case 2: QCOMPARE(buf[0], 'b'); break; + case 3: QCOMPARE(buf[0], 'a'); break; + case 4: QCOMPARE(buf[0], '\0'); break; + } + QCOMPARE(buf[1], i < 4 ? '\0' : '@'); + } + + buffer.ungetChar('\n'); + QCOMPARE(buffer.readLine(), QByteArray("\n")); + + buffer.seek(1); + buffer.readLine(buf, 3); + QCOMPARE(static_cast<const char*>(buf), "XC"); + + buffer.seek(4); + buffer.ungetChar('Q'); + QCOMPARE(buffer.readLine(buf, 3), qint64(1)); + + for (int i = 0; i < 2; ++i) { + QTcpSocket socket; + QIODevice *dev; + QByteArray result; + const char *lineResult; + if (i == 0) { + dev = &buffer; + result = QByteArray("ZXCV"); + lineResult = "ZXCV"; + } else { + socket.connectToHost(QtNetworkSettings::serverName(), 80); + socket.write("GET / HTTP/1.0\r\n\r\n"); + QVERIFY(socket.waitForReadyRead()); + dev = &socket; + result = QByteArray("HTTP"); + lineResult = "Date"; + } + char ch, ch2; + dev->seek(0); + dev->getChar(&ch); + dev->ungetChar(ch); + QCOMPARE(dev->peek(4), result); + dev->getChar(&ch); + dev->getChar(&ch2); + dev->ungetChar(ch2); + dev->ungetChar(ch); + QCOMPARE(dev->read(1), result.left(1)); + QCOMPARE(dev->read(3), result.right(3)); + + if (i == 0) + dev->seek(0); + else + dev->readLine(); + dev->getChar(&ch); + dev->ungetChar(ch); + dev->readLine(buf, 5); + QCOMPARE(static_cast<const char*>(buf), lineResult); + + if (i == 1) + socket.close(); + } +} + +//-------------------------------------------------------------------- +void tst_QIODevice::peek() +{ + QBuffer buffer; + QFile::remove("peektestfile"); + QFile file("peektestfile"); + + for (int i = 0; i < 2; ++i) { + QIODevice *device = i ? (QIODevice *)&file : (QIODevice *)&buffer; + + device->open(QBuffer::ReadWrite); + device->write("ZXCV"); + + device->seek(0); + QCOMPARE(device->peek(4), QByteArray("ZXCV")); + QCOMPARE(device->pos(), qint64(0)); + device->write("ABCDE"); + device->seek(3); + QCOMPARE(device->peek(1), QByteArray("D")); + QCOMPARE(device->peek(5), QByteArray("DE")); + device->seek(0); + QCOMPARE(device->read(4), QByteArray("ABCD")); + QCOMPARE(device->pos(), qint64(4)); + + device->seek(0); + device->write("ZXCV"); + device->seek(0); + char buf[5]; + buf[4] = 0; + device->peek(buf, 4); + QCOMPARE(static_cast<const char *>(buf), "ZXCV"); + QCOMPARE(device->pos(), qint64(0)); + device->read(buf, 4); + QCOMPARE(static_cast<const char *>(buf), "ZXCV"); + QCOMPARE(device->pos(), qint64(4)); + } + QFile::remove("peektestfile"); +} + +void tst_QIODevice::peekAndRead() +{ + QByteArray originalData; + for (int i=0;i<1000;i++) + originalData += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QBuffer buffer; + QFile::remove("peektestfile"); + QFile file("peektestfile"); + + for (int i = 0; i < 2; ++i) { + QByteArray readData; + QIODevice *device = i ? (QIODevice *)&file : (QIODevice *)&buffer; + device->open(QBuffer::ReadWrite); + device->write(originalData); + device->seek(0); + while (!device->atEnd()) { + char peekIn[26]; + device->peek(peekIn, 26); + readData += device->read(26); + } + QCOMPARE(readData, originalData); + } + QFile::remove("peektestfile"); +} + +void tst_QIODevice::readLine_data() +{ + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << QByteArray("\nAA"); + QTest::newRow("1") << QByteArray("A\nAA"); + + QByteArray data(9000, 'A'); + data[8193] = '\n'; + QTest::newRow("8194") << data; + data[8193] = 'A'; + data[8192] = '\n'; + QTest::newRow("8193") << data; + data[8192] = 'A'; + data[8191] = '\n'; + QTest::newRow("8192") << data; + data[8191] = 'A'; + data[8190] = '\n'; + QTest::newRow("8191") << data; + + data[5999] = '\n'; + QTest::newRow("6000") << data; + + data[4095] = '\n'; + QTest::newRow("4096") << data; + + data[4094] = '\n'; + data[4095] = 'A'; + QTest::newRow("4095") << data; +} + +void tst_QIODevice::readLine() +{ + QFETCH(QByteArray, data); + QBuffer buffer(&data); + QVERIFY(buffer.open(QIODevice::ReadWrite)); + QVERIFY(buffer.canReadLine()); + + int linelen = data.indexOf('\n') + 1; + QByteArray line; + line.reserve(linelen + 100); + + int result = buffer.readLine(line.data(), linelen + 100); + QCOMPARE(result, linelen); + + // try the exact length of the line (plus terminating \0) + QVERIFY(buffer.seek(0)); + result = buffer.readLine(line.data(), linelen + 1); + QCOMPARE(result, linelen); + + // try with a line length limit + QVERIFY(buffer.seek(0)); + line = buffer.readLine(linelen + 100); + QCOMPARE(line.size(), linelen); + + // try without a length limit + QVERIFY(buffer.seek(0)); + line = buffer.readLine(); + QCOMPARE(line.size(), linelen); +} + +void tst_QIODevice::readLine2_data() +{ + QTest::addColumn<QByteArray>("line"); + + QTest::newRow("1024 - 4") << QByteArray(1024 - 4, 'x'); + QTest::newRow("1024 - 3") << QByteArray(1024 - 3, 'x'); + QTest::newRow("1024 - 2") << QByteArray(1024 - 2, 'x'); + QTest::newRow("1024 - 1") << QByteArray(1024 - 1, 'x'); + QTest::newRow("1024" ) << QByteArray(1024 , 'x'); + QTest::newRow("1024 + 1") << QByteArray(1024 + 1, 'x'); + QTest::newRow("1024 + 2") << QByteArray(1024 + 2, 'x'); + + QTest::newRow("4096 - 4") << QByteArray(4096 - 4, 'x'); + QTest::newRow("4096 - 3") << QByteArray(4096 - 3, 'x'); + QTest::newRow("4096 - 2") << QByteArray(4096 - 2, 'x'); + QTest::newRow("4096 - 1") << QByteArray(4096 - 1, 'x'); + QTest::newRow("4096" ) << QByteArray(4096 , 'x'); + QTest::newRow("4096 + 1") << QByteArray(4096 + 1, 'x'); + QTest::newRow("4096 + 2") << QByteArray(4096 + 2, 'x'); + + QTest::newRow("8192 - 4") << QByteArray(8192 - 4, 'x'); + QTest::newRow("8192 - 3") << QByteArray(8192 - 3, 'x'); + QTest::newRow("8192 - 2") << QByteArray(8192 - 2, 'x'); + QTest::newRow("8192 - 1") << QByteArray(8192 - 1, 'x'); + QTest::newRow("8192" ) << QByteArray(8192 , 'x'); + QTest::newRow("8192 + 1") << QByteArray(8192 + 1, 'x'); + QTest::newRow("8192 + 2") << QByteArray(8192 + 2, 'x'); + + QTest::newRow("16384 - 4") << QByteArray(16384 - 4, 'x'); + QTest::newRow("16384 - 3") << QByteArray(16384 - 3, 'x'); + QTest::newRow("16384 - 2") << QByteArray(16384 - 2, 'x'); + QTest::newRow("16384 - 1") << QByteArray(16384 - 1, 'x'); + QTest::newRow("16384" ) << QByteArray(16384 , 'x'); + QTest::newRow("16384 + 1") << QByteArray(16384 + 1, 'x'); + QTest::newRow("16384 + 2") << QByteArray(16384 + 2, 'x'); + + QTest::newRow("20000") << QByteArray(20000, 'x'); + + QTest::newRow("32768 - 4") << QByteArray(32768 - 4, 'x'); + QTest::newRow("32768 - 3") << QByteArray(32768 - 3, 'x'); + QTest::newRow("32768 - 2") << QByteArray(32768 - 2, 'x'); + QTest::newRow("32768 - 1") << QByteArray(32768 - 1, 'x'); + QTest::newRow("32768" ) << QByteArray(32768 , 'x'); + QTest::newRow("32768 + 1") << QByteArray(32768 + 1, 'x'); + QTest::newRow("32768 + 2") << QByteArray(32768 + 2, 'x'); + + QTest::newRow("40000") << QByteArray(40000, 'x'); +} + +void tst_QIODevice::readLine2() +{ + QFETCH(QByteArray, line); + + int length = line.size(); + + QByteArray data("First line.\r\n"); + data.append(line); + data.append("\r\n"); + data.append(line); + data.append("\r\n"); + data.append("\r\n0123456789"); + + { + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + + buffer.seek(0); + QByteArray temp; + temp.resize(64536); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(13)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 2)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 2)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(2)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(10)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(-1)); + + buffer.seek(0); + QCOMPARE(buffer.readLine().size(), 13); + QCOMPARE(buffer.readLine().size(), length + 2); + QCOMPARE(buffer.readLine().size(), length + 2); + QCOMPARE(buffer.readLine().size(), 2); + QCOMPARE(buffer.readLine().size(), 10); + QVERIFY(buffer.readLine().isNull()); + } + + { + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly | QIODevice::Text); + + buffer.seek(0); + QByteArray temp; + temp.resize(64536); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(12)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 1)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(length + 1)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(1)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(10)); + QCOMPARE(buffer.readLine(temp.data(), temp.size()), qint64(-1)); + + buffer.seek(0); + QCOMPARE(buffer.readLine().size(), 12); + QCOMPARE(buffer.readLine().size(), length + 1); + QCOMPARE(buffer.readLine().size(), length + 1); + QCOMPARE(buffer.readLine().size(), 1); + QCOMPARE(buffer.readLine().size(), 10); + QVERIFY(buffer.readLine().isNull()); + } +} + + +class PeekBug : public QIODevice { + Q_OBJECT +public: + char alphabet[27]; + qint64 counter; + PeekBug() : QIODevice(), counter(0) { + memcpy(alphabet,"abcdefghijklmnopqrstuvqxyz",27); + }; + qint64 readData(char *data, qint64 maxlen) { + qint64 pos = 0; + while (pos < maxlen) { + *(data + pos) = alphabet[counter]; + pos++; + counter++; + if (counter == 26) + counter = 0; + } + return maxlen; + } + qint64 writeData(const char * /* data */, qint64 /* maxlen */) { + return -1; + } + +}; + +// This is a testcase for the bug fixed with bd287865 +void tst_QIODevice::peekBug() +{ + PeekBug peekBug; + peekBug.open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + char onetwo[2]; + peekBug.peek(onetwo, 2); + QCOMPARE(onetwo[0], 'a'); + QCOMPARE(onetwo[1], 'b'); + + peekBug.read(onetwo, 1); + QCOMPARE(onetwo[0], 'a'); + + peekBug.peek(onetwo, 2); + QCOMPARE(onetwo[0], 'b'); + QCOMPARE(onetwo[1], 'c'); + + peekBug.read(onetwo, 1); + QCOMPARE(onetwo[0], 'b'); + peekBug.read(onetwo, 1); + QCOMPARE(onetwo[0], 'c'); + peekBug.read(onetwo, 1); + QCOMPARE(onetwo[0], 'd'); + + peekBug.peek(onetwo, 2); + QCOMPARE(onetwo[0], 'e'); + QCOMPARE(onetwo[1], 'f'); + +} + +QTEST_MAIN(tst_QIODevice) +#include "tst_qiodevice.moc" diff --git a/tests/auto/corelib/io/qprocess/.gitignore b/tests/auto/corelib/io/qprocess/.gitignore new file mode 100644 index 0000000000..a273810042 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/.gitignore @@ -0,0 +1,22 @@ +tst_qprocess +fileWriterProcess/fileWriterProcess +test Space In Name/ +testDetached/testDetached +testExitCodes/testExitCodes +testGuiProcess/testGuiProcess +testProcessCrash/testProcessCrash +testProcessDeadWhileReading/testProcessDeadWhileReading +testProcessEOF/testProcessEOF +testProcessEcho/testProcessEcho +testProcessEcho2/testProcessEcho2 +testProcessEcho3/testProcessEcho3 +testProcessEnvironment/testProcessEnvironment +testProcessLoopback/testProcessLoopback +testProcessNormal/testProcessNormal +testProcessOutput/testProcessOutput +testProcessSpacesArgs/nospace +testProcessSpacesArgs/one space +testProcessSpacesArgs/two space s +testSetWorkingDirectory/testSetWorkingDirectory +testSoftExit/testSoftExit +data diff --git a/tests/auto/corelib/io/qprocess/fileWriterProcess/fileWriterProcess.pro b/tests/auto/corelib/io/qprocess/fileWriterProcess/fileWriterProcess.pro new file mode 100644 index 0000000000..c9f87ba361 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/fileWriterProcess/fileWriterProcess.pro @@ -0,0 +1,10 @@ +SOURCES = main.cpp +CONFIG += console +CONFIG -= app_bundle +QT = core +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/fileWriterProcess/main.cpp b/tests/auto/corelib/io/qprocess/fileWriterProcess/main.cpp new file mode 100644 index 0000000000..40e92c69be --- /dev/null +++ b/tests/auto/corelib/io/qprocess/fileWriterProcess/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtCore> + +int main(int argc, char **argv) +{ + QCoreApplication ca(argc, argv); + QFile f; + f.open(stdin, QIODevice::ReadOnly); + QString input; + char buf[1024]; + qint64 len; + while ((len = f.read(buf, 1024)) > 0) + input += QByteArray(buf, len); + f.close(); + QFile f2("fileWriterProcess.txt"); + f2.open(QIODevice::WriteOnly | QIODevice::Truncate); + f2.write(input.toLatin1()); + f2.close(); + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/qprocess.pro b/tests/auto/corelib/io/qprocess/qprocess.pro new file mode 100644 index 0000000000..77cfc8252e --- /dev/null +++ b/tests/auto/corelib/io/qprocess/qprocess.pro @@ -0,0 +1,32 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + testProcessCrash \ + testProcessEcho \ + testProcessEcho2 \ + testProcessEcho3 \ + testProcessEnvironment \ + testProcessLoopback \ + testProcessNormal \ + testProcessOutput \ + testProcessDeadWhileReading \ + testProcessEOF \ + testProcessSpacesArgs/nospace.pro \ + testExitCodes \ + testSpaceInName \ + testGuiProcess \ + testDetached \ + fileWriterProcess \ + testSetWorkingDirectory + +!symbian: { +SUBDIRS +=testProcessSpacesArgs/onespace.pro \ + testProcessSpacesArgs/twospaces.pro \ + testSoftExit +} + +win32:!wince*:SUBDIRS+=testProcessEchoGui + +SUBDIRS += test + + diff --git a/tests/auto/corelib/io/qprocess/test/test.pro b/tests/auto/corelib/io/qprocess/test/test.pro new file mode 100644 index 0000000000..a91caddd2f --- /dev/null +++ b/tests/auto/corelib/io/qprocess/test/test.pro @@ -0,0 +1,124 @@ +load(qttest_p4) + +SOURCES += ../tst_qprocess.cpp +!wince*: { +TARGET = ../tst_qprocess + +win32: { + CONFIG(debug, debug|release) { + TARGET = ../../debug/tst_qprocess +} else { + TARGET = ../../release/tst_qprocess + } +} +} else { + TARGET = tst_qprocess +} + + + +QT = core + +!symbian: { + QT += network +} + +embedded: QT += gui + +wince*: { + + addFile_fileWriterProcess.files = $$OUT_PWD/../fileWriterProcess/fileWriterProcess.exe + addFile_fileWriterProcess.path = fileWriterProcess + + addFile_testBatFiles.files = $$PWD/../testBatFiles/* + addFile_testBatFiles.path = testBatFiles + + addFile_testDetached.files = $$OUT_PWD/../testDetached/testDetached.exe + addFile_testDetached.path = testDetached + + addFile_testExitCodes.files = $$OUT_PWD/../testExitCodes/testExitCodes.exe + addFile_testExitCodes.path = testExitCodes + + addFile_testGuiProcess.files = $$OUT_PWD/../testGuiProcess/testGuiProcess.exe + addFile_testGuiProcess.path = testGuiProcess + + addFile_testProcessCrash.files = $$OUT_PWD/../testProcessCrash/testProcessCrash.exe + addFile_testProcessCrash.path = testProcessCrash + + addFile_testProcessDeadWhileReading.files = $$OUT_PWD/../testProcessDeadWhileReading/testProcessDeadWhileReading.exe + addFile_testProcessDeadWhileReading.path = testProcessDeadWhileReading + + addFile_testProcessEcho.files = $$OUT_PWD/../testProcessEcho/testProcessEcho.exe + addFile_testProcessEcho.path = testProcessEcho + + addFile_testProcessEcho2.files = $$OUT_PWD/../testProcessEcho2/testProcessEcho2.exe + addFile_testProcessEcho2.path = testProcessEcho2 + + addFile_testProcessEcho3.files = $$OUT_PWD/../testProcessEcho3/testProcessEcho3.exe + addFile_testProcessEcho3.path = testProcessEcho3 + + addFile_testProcessEOF.files = $$OUT_PWD/../testProcessEOF/testProcessEOF.exe + addFile_testProcessEOF.path = testProcessEOF + + addFile_testProcessLoopback.files = $$OUT_PWD/../testProcessLoopback/testProcessLoopback.exe + addFile_testProcessLoopback.path = testProcessLoopback + + addFile_testProcessNormal.files = $$OUT_PWD/../testProcessNormal/testProcessNormal.exe + addFile_testProcessNormal.path = testProcessNormal + + addFile_testProcessOutput.files = $$OUT_PWD/../testProcessOutput/testProcessOutput.exe + addFile_testProcessOutput.path = testProcessOutput + + addFile_testProcessNoSpacesArgs.files = $$OUT_PWD/../testProcessSpacesArgs/nospace.exe + addFile_testProcessNoSpacesArgs.path = testProcessSpacesArgs + + addFile_testProcessOneSpacesArgs.files = $$OUT_PWD/../testProcessSpacesArgs/"one space".exe + addFile_testProcessOneSpacesArgs.path = testProcessSpacesArgs + + addFile_testProcessTwoSpacesArgs.files = $$OUT_PWD/../testProcessSpacesArgs/"two space s".exe + addFile_testProcessTwoSpacesArgs.path = testProcessSpacesArgs + + addFile_testSoftExit.files = $$OUT_PWD/../testSoftExit/testSoftExit.exe + addFile_testSoftExit.path = testSoftExit + + addFile_testSpaceInName.files = $$OUT_PWD/../"test Space In Name"/testSpaceInName.exe + addFile_testSpaceInName.path = "test Space In Name" + + + DEPLOYMENT += addFile_fileWriterProcess \ + addFile_testBatFiles \ + addFile_testDetached \ + addFile_testExitCodes \ + addFile_testGuiProcess \ + addFile_testProcessCrash \ + addFile_testProcessDeadWhileReading \ + addFile_testProcessEcho \ + addFile_testProcessEcho2 \ + addFile_testProcessEcho3 \ + addFile_testProcessEchoGui \ + addFile_testProcessEOF \ + addFile_testProcessLoopback \ + addFile_testProcessNormal \ + addFile_testProcessOutput \ + addFile_testProcessNoSpacesArgs \ + addFile_testProcessOneSpacesArgs \ + addFile_testProcessTwoSpacesArgs \ + addFile_testSoftExit \ + addFile_testSpaceInName +} + +symbian: { + binDep.files = \ + fileWriterProcess.exe \ + testDetached.exe \ + testExitCodes.exe \ + testProcessCrash.exe \ + testProcessEcho.exe \ + testProcessNormal.exe \ + testProcessOutput.exe \ + nospace.exe \ + testSpaceInName.exe + binDep.path = \\sys\\bin + + DEPLOYMENT += binDep +} diff --git a/tests/auto/corelib/io/qprocess/testBatFiles/simple.bat b/tests/auto/corelib/io/qprocess/testBatFiles/simple.bat new file mode 100755 index 0000000000..900f7ae356 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testBatFiles/simple.bat @@ -0,0 +1,2 @@ +@echo off +echo Hello
\ No newline at end of file diff --git a/tests/auto/corelib/io/qprocess/testBatFiles/with space.bat b/tests/auto/corelib/io/qprocess/testBatFiles/with space.bat new file mode 100755 index 0000000000..900f7ae356 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testBatFiles/with space.bat @@ -0,0 +1,2 @@ +@echo off +echo Hello
\ No newline at end of file diff --git a/tests/auto/corelib/io/qprocess/testDetached/main.cpp b/tests/auto/corelib/io/qprocess/testDetached/main.cpp new file mode 100644 index 0000000000..5b4ee790b9 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testDetached/main.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QCoreApplication> +#include <QDebug> +#include <QStringList> +#include <QFile> +#include <QDir> + +#include <stdio.h> + +#if defined(Q_OS_UNIX) +#include <sys/types.h> +#include <unistd.h> +#elif defined(Q_OS_WIN) +#include <windows.h> +#endif + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QStringList args = app.arguments(); + if (args.count() != 2) { + fprintf(stderr, "Usage: testDetached filename.txt\n"); + return 128; + } + + QFile f(args.at(1)); + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + fprintf(stderr, "Cannot open %s for writing", qPrintable(f.fileName())); + return 1; + } + + f.write(QDir::currentPath().toUtf8()); + f.putChar('\n'); +#if defined(Q_OS_UNIX) + f.write(QByteArray::number(quint64(getpid()))); +#elif defined(Q_OS_WIN) + f.write(QByteArray::number(quint64(GetCurrentProcessId()))); +#endif + f.putChar('\n'); + + f.close(); + + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testDetached/testDetached.pro b/tests/auto/corelib/io/qprocess/testDetached/testDetached.pro new file mode 100644 index 0000000000..80a616b3e9 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testDetached/testDetached.pro @@ -0,0 +1,10 @@ +SOURCES = main.cpp +QT = core +CONFIG += console +CONFIG -= app_bundle +INSTALLS = +DESTDIR = ./ + +symbian: { +TARGET.EPOCSTACKSIZE =0x14000 +} diff --git a/tests/auto/corelib/io/qprocess/testExitCodes/main.cpp b/tests/auto/corelib/io/qprocess/testExitCodes/main.cpp new file mode 100644 index 0000000000..4d6a49e8f5 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testExitCodes/main.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdlib.h> +int main(int /* argc */, char **argv) +{ + return atoi(argv[1]); +} + diff --git a/tests/auto/corelib/io/qprocess/testExitCodes/testExitCodes.pro b/tests/auto/corelib/io/qprocess/testExitCodes/testExitCodes.pro new file mode 100644 index 0000000000..b08371804f --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testExitCodes/testExitCodes.pro @@ -0,0 +1,5 @@ +SOURCES += main.cpp +CONFIG -= qt app_bundle +CONFIG += console + +DESTDIR = ./ diff --git a/tests/auto/corelib/io/qprocess/testGuiProcess/main.cpp b/tests/auto/corelib/io/qprocess/testGuiProcess/main.cpp new file mode 100644 index 0000000000..90d4d4a962 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testGuiProcess/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtWidgets/QApplication> +#include <QtWidgets/QLabel> +#include <stdio.h> + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + QLabel label("This process is just waiting to die"); + label.show(); + + int c; + Q_UNUSED(c); + fgetc(stdin); // block until fed + + qDebug("Process is running"); + + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testGuiProcess/testGuiProcess.pro b/tests/auto/corelib/io/qprocess/testGuiProcess/testGuiProcess.pro new file mode 100644 index 0000000000..b26a583dee --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testGuiProcess/testGuiProcess.pro @@ -0,0 +1,5 @@ +SOURCES += main.cpp +QT += widgets +CONFIG += console +DESTDIR = ./ + diff --git a/tests/auto/corelib/io/qprocess/testProcessCrash/main.cpp b/tests/auto/corelib/io/qprocess/testProcessCrash/main.cpp new file mode 100644 index 0000000000..e2ec87b3aa --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessCrash/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +struct Foo +{ + int i; +}; + +int main() +{ + *(char*)0 = 0; + Foo *f = 0; + return f->i; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessCrash/testProcessCrash.pro b/tests/auto/corelib/io/qprocess/testProcessCrash/testProcessCrash.pro new file mode 100644 index 0000000000..abd8167313 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessCrash/testProcessCrash.pro @@ -0,0 +1,8 @@ +SOURCES = main.cpp +CONFIG += console +CONFIG -= qt app_bundle + +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = diff --git a/tests/auto/corelib/io/qprocess/testProcessDeadWhileReading/main.cpp b/tests/auto/corelib/io/qprocess/testProcessDeadWhileReading/main.cpp new file mode 100644 index 0000000000..9e285b5012 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessDeadWhileReading/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main() +{ + for (int i=0; i<10240; i++) + fprintf(stdout, "%d dead while reading\n", i); + fflush(stdout); + + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessDeadWhileReading/testProcessDeadWhileReading.pro b/tests/auto/corelib/io/qprocess/testProcessDeadWhileReading/testProcessDeadWhileReading.pro new file mode 100644 index 0000000000..2168ba5672 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessDeadWhileReading/testProcessDeadWhileReading.pro @@ -0,0 +1,10 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console + +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/testProcessEOF/main.cpp b/tests/auto/corelib/io/qprocess/testProcessEOF/main.cpp new file mode 100644 index 0000000000..28de5c2f3a --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEOF/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> +#include <string.h> + +int main() +{ + char buf[32]; + memset(buf, 0, sizeof(buf)); + + char *cptr = buf; + int c; + while (cptr != buf + 31 && (c = fgetc(stdin)) != EOF) + *cptr++ = (char) c; + + printf("%s", buf); + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessEOF/testProcessEOF.pro b/tests/auto/corelib/io/qprocess/testProcessEOF/testProcessEOF.pro new file mode 100644 index 0000000000..756bd23bb0 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEOF/testProcessEOF.pro @@ -0,0 +1,9 @@ +SOURCES = main.cpp +CONFIG -= qt app_bundle +CONFIG += console + +win32:!win32-g++*:!equals(TEMPLATE_PREFIX, "vc"):QMAKE_CXXFLAGS += /GS- +DESTDIR = ./ + + + diff --git a/tests/auto/corelib/io/qprocess/testProcessEcho/main.cpp b/tests/auto/corelib/io/qprocess/testProcessEcho/main.cpp new file mode 100644 index 0000000000..a7eedff56d --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEcho/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main() +{ +#if defined(_WIN32_WCE) && defined(_X86_) + return 0; +#else + int c; + while ((c = fgetc(stdin)) != -1) { + if (c == '\0') + break; + fputc(c, stdout); + fflush(stdout); + } + return 0; +#endif +} diff --git a/tests/auto/corelib/io/qprocess/testProcessEcho/testProcessEcho.pro b/tests/auto/corelib/io/qprocess/testProcessEcho/testProcessEcho.pro new file mode 100644 index 0000000000..a14c1fe163 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEcho/testProcessEcho.pro @@ -0,0 +1,8 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + diff --git a/tests/auto/corelib/io/qprocess/testProcessEcho2/main.cpp b/tests/auto/corelib/io/qprocess/testProcessEcho2/main.cpp new file mode 100644 index 0000000000..1c18319bca --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEcho2/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main() +{ + int c; + while ((c = fgetc(stdin)) != -1) { + if (c == '\0') + break; + fputc(c, stdout); + fputc(c, stderr); + fflush(stdout); + fflush(stderr); + } + + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessEcho2/testProcessEcho2.pro b/tests/auto/corelib/io/qprocess/testProcessEcho2/testProcessEcho2.pro new file mode 100644 index 0000000000..d8a303a22b --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEcho2/testProcessEcho2.pro @@ -0,0 +1,10 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + + diff --git a/tests/auto/corelib/io/qprocess/testProcessEcho3/main.cpp b/tests/auto/corelib/io/qprocess/testProcessEcho3/main.cpp new file mode 100644 index 0000000000..62901a7789 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEcho3/main.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main() +{ + int c; + for (;;) { + c = fgetc(stdin); + if (c == '\0') + break; + if (c != -1) { + fputc(c, stdout); + fputc(c, stderr); + fflush(stdout); + fflush(stderr); + } + } + + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessEcho3/testProcessEcho3.pro b/tests/auto/corelib/io/qprocess/testProcessEcho3/testProcessEcho3.pro new file mode 100644 index 0000000000..3b8f2fb0d7 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEcho3/testProcessEcho3.pro @@ -0,0 +1,9 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/testProcessEchoGui/main_win.cpp b/tests/auto/corelib/io/qprocess/testProcessEchoGui/main_win.cpp new file mode 100644 index 0000000000..b8c2bd6abd --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEchoGui/main_win.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <windows.h> + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + + HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); + + for (;;) { + + char c = 0; + DWORD read = 0; + if (!ReadFile(hStdin, &c, 1, &read, 0) || read == 0 || c == 'q' || c == '\0') + break; + DWORD wrote = 0; + WriteFile(hStdout, &c, 1, &wrote, 0); + WriteFile(hStderr, &c, 1, &wrote, 0); + } + return 0; +}
\ No newline at end of file diff --git a/tests/auto/corelib/io/qprocess/testProcessEchoGui/testProcessEchoGui.pro b/tests/auto/corelib/io/qprocess/testProcessEchoGui/testProcessEchoGui.pro new file mode 100644 index 0000000000..b3be74cbd1 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEchoGui/testProcessEchoGui.pro @@ -0,0 +1,13 @@ +win32 { + SOURCES = main_win.cpp + !win32-borland:LIBS += -lUser32 +} + +CONFIG -= qt +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + + diff --git a/tests/auto/corelib/io/qprocess/testProcessEnvironment/main.cpp b/tests/auto/corelib/io/qprocess/testProcessEnvironment/main.cpp new file mode 100644 index 0000000000..17ed5c61dc --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEnvironment/main.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char **argv) +{ +#if defined(_WIN32_WCE) + // no environment in Windows CE + return 0; +#else + if (argc == 1) + return 1; + + char *env = getenv(argv[1]); + if (env) { + printf("%s", env); + return 0; + } + return 1; +#endif +} diff --git a/tests/auto/corelib/io/qprocess/testProcessEnvironment/testProcessEnvironment.pro b/tests/auto/corelib/io/qprocess/testProcessEnvironment/testProcessEnvironment.pro new file mode 100644 index 0000000000..14ddae50f3 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessEnvironment/testProcessEnvironment.pro @@ -0,0 +1,12 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = ./ + +mac { + CONFIG -= app_bundle +} + +# no install rule for application used by test +INSTALLS = + diff --git a/tests/auto/corelib/io/qprocess/testProcessLoopback/main.cpp b/tests/auto/corelib/io/qprocess/testProcessLoopback/main.cpp new file mode 100644 index 0000000000..6803518400 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessLoopback/main.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main() +{ + char buffer[1024]; + for (;;) { + size_t num = fread(buffer, 1, sizeof(buffer), stdin); + if (num <= 0) + break; + fwrite(buffer, num, 1, stdout); + fflush(stdout); + } + + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessLoopback/testProcessLoopback.pro b/tests/auto/corelib/io/qprocess/testProcessLoopback/testProcessLoopback.pro new file mode 100644 index 0000000000..a14c1fe163 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessLoopback/testProcessLoopback.pro @@ -0,0 +1,8 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + diff --git a/tests/auto/corelib/io/qprocess/testProcessNormal/main.cpp b/tests/auto/corelib/io/qprocess/testProcessNormal/main.cpp new file mode 100644 index 0000000000..008a0a2430 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessNormal/main.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +int main() +{ + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessNormal/testProcessNormal.pro b/tests/auto/corelib/io/qprocess/testProcessNormal/testProcessNormal.pro new file mode 100644 index 0000000000..3c6a595d85 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessNormal/testProcessNormal.pro @@ -0,0 +1,9 @@ +SOURCES = main.cpp +CONFIG += console +CONFIG -= qt app_bundle + +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + diff --git a/tests/auto/corelib/io/qprocess/testProcessOutput/main.cpp b/tests/auto/corelib/io/qprocess/testProcessOutput/main.cpp new file mode 100644 index 0000000000..b648d1bec3 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessOutput/main.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main() +{ +#if defined(__SYMBIAN32__) + // Printing to stdout messes up the out.txt, so open a file and print there. + FILE* file = fopen("c:\\logs\\qprocess_output_test.txt","w+"); + for (int i=0; i<200; i++) { + fprintf(file, "%d -this is a number\n", i); + fflush(file); + } + fclose(file); +#else +# if defined(_WIN32_WCE) + for (int i=0; i<240; i++) { +# else //fprintf Output is very slow on Windows CE/Symbian + for (int i=0; i<10240; i++) { +# endif + fprintf(stdout, "%d -this is a number\n", i); + fflush(stderr); + } +#endif + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessOutput/testProcessOutput.pro b/tests/auto/corelib/io/qprocess/testProcessOutput/testProcessOutput.pro new file mode 100644 index 0000000000..3b8f2fb0d7 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessOutput/testProcessOutput.pro @@ -0,0 +1,9 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/main.cpp b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/main.cpp new file mode 100644 index 0000000000..39a0b3bac1 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main(int argc, char ** argv) +{ +#if defined(__SYMBIAN32__) || defined(WINCE) || defined(_WIN32_WCE) +# if defined(__SYMBIAN32__) + // Printing to stdout messes up the out.txt, so open a file and print there. + FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","w+"); +# else + // No pipes on this "OS" + FILE* file = fopen("\\temp\\qprocess_args_test.txt","w+"); +# endif + for (int i = 0; i < argc; ++i) { + if (i) + fprintf(file, "|"); + fprintf(file, argv[i]); + } + fclose(file); +#else + for (int i = 0; i < argc; ++i) { + if (i) + printf("|"); + printf("%s", argv[i]); + } +#endif + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/nospace.pro b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/nospace.pro new file mode 100644 index 0000000000..f55f02e425 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/nospace.pro @@ -0,0 +1,9 @@ +SOURCES = main.cpp +CONFIG -= qt app_bundle +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/onespace.pro b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/onespace.pro new file mode 100644 index 0000000000..2a56a95606 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/onespace.pro @@ -0,0 +1,11 @@ +SOURCES = main.cpp +CONFIG -= qt app_bundle +CONFIG += console +DESTDIR = ./ + +TARGET = "one space" + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/twospaces.pro b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/twospaces.pro new file mode 100644 index 0000000000..d7c74a64c9 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testProcessSpacesArgs/twospaces.pro @@ -0,0 +1,12 @@ +SOURCES = main.cpp +CONFIG -= qt app_bundle +CONFIG += console +DESTDIR = ./ + +TARGET = "two space s" + +# no install rule for application used by test +INSTALLS = + + + diff --git a/tests/auto/corelib/io/qprocess/testSetWorkingDirectory/main.cpp b/tests/auto/corelib/io/qprocess/testSetWorkingDirectory/main.cpp new file mode 100644 index 0000000000..0035c6253a --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testSetWorkingDirectory/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore> + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + QByteArray currentPath = QDir::currentPath().toLocal8Bit(); + fprintf(stdout, "%s", currentPath.constData()); + app.exit(); +} diff --git a/tests/auto/corelib/io/qprocess/testSetWorkingDirectory/testSetWorkingDirectory.pro b/tests/auto/corelib/io/qprocess/testSetWorkingDirectory/testSetWorkingDirectory.pro new file mode 100644 index 0000000000..b723604171 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testSetWorkingDirectory/testSetWorkingDirectory.pro @@ -0,0 +1,7 @@ +SOURCES = main.cpp +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + diff --git a/tests/auto/corelib/io/qprocess/testSoftExit/main_unix.cpp b/tests/auto/corelib/io/qprocess/testSoftExit/main_unix.cpp new file mode 100644 index 0000000000..b17ab4d9a6 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testSoftExit/main_unix.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +int main() +{ + struct sigaction noaction; + memset(&noaction, 0, sizeof(noaction)); + noaction.sa_handler = SIG_IGN; + ::sigaction(SIGTERM, &noaction, 0); + + printf("Ready\n"); + fflush(stdout); + + for (int i = 0; i < 5; ++i) + sleep(1); + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testSoftExit/main_win.cpp b/tests/auto/corelib/io/qprocess/testSoftExit/main_win.cpp new file mode 100644 index 0000000000..29dbc46bcf --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testSoftExit/main_win.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <windows.h> +#include <stdio.h> + +int main() +{ + printf("Ready\n"); + fflush(stdout); + + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + if (msg.message == WM_CLOSE) + PostQuitMessage(0); + } + + return msg.wParam; +} diff --git a/tests/auto/corelib/io/qprocess/testSoftExit/testSoftExit.pro b/tests/auto/corelib/io/qprocess/testSoftExit/testSoftExit.pro new file mode 100644 index 0000000000..922035907a --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testSoftExit/testSoftExit.pro @@ -0,0 +1,16 @@ +win32 { + SOURCES = main_win.cpp + !win32-borland:!wince*:LIBS += -lUser32 +} +unix { + SOURCES = main_unix.cpp +} + +CONFIG -= qt app_bundle +CONFIG += console +DESTDIR = ./ + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/testSpaceInName/main.cpp b/tests/auto/corelib/io/qprocess/testSpaceInName/main.cpp new file mode 100644 index 0000000000..3fadc68095 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testSpaceInName/main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <stdio.h> + +int main() +{ + int c; + while ((c = fgetc(stdin)) != -1) { + if (c == '\0') + break; + fputc(c, stdout); + fflush(stdout); + } + + return 0; +} diff --git a/tests/auto/corelib/io/qprocess/testSpaceInName/testSpaceInName.pro b/tests/auto/corelib/io/qprocess/testSpaceInName/testSpaceInName.pro new file mode 100644 index 0000000000..913e868d03 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/testSpaceInName/testSpaceInName.pro @@ -0,0 +1,13 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = "../test Space In Name" + +mac { + CONFIG -= app_bundle +} + +# no install rule for application used by test +INSTALLS = + + diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp new file mode 100644 index 0000000000..9873c3e357 --- /dev/null +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -0,0 +1,2472 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore/QProcess> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QThread> +#include <QtCore/QRegExp> +#include <QtCore/QDebug> +#include <QtCore/QMetaType> +#if !defined(Q_OS_SYMBIAN) +// Network test unnecessary? +#include <QtNetwork/QHostInfo> +#endif +#include <stdlib.h> + +#ifdef QT_NO_PROCESS +QTEST_NOOP_MAIN +#else + +#if defined(Q_OS_WIN) +#include <windows.h> +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +Q_DECLARE_METATYPE(QList<QProcess::ExitStatus>); +Q_DECLARE_METATYPE(QProcess::ExitStatus); +Q_DECLARE_METATYPE(QProcess::ProcessState); + +#define QPROCESS_VERIFY(Process, Fn) \ +{ \ +const bool ret = Process.Fn; \ +if (ret == false) \ + qWarning("QProcess error: %d: %s", Process.error(), qPrintable(Process.errorString())); \ +QVERIFY(ret); \ +} + +class tst_QProcess : public QObject +{ + Q_OBJECT + +public: + tst_QProcess(); + virtual ~tst_QProcess(); + +public slots: + void init(); + void cleanup(); + +private slots: + void getSetCheck(); + void constructing(); + void simpleStart(); + void execute(); + void startDetached(); + void crashTest(); + void crashTest2(); + void echoTest_data(); + void echoTest(); + void echoTest2(); + void echoTest_performance(); +#if defined Q_OS_WIN + void echoTestGui(); + void batFiles_data(); + void batFiles(); +#endif + void exitStatus_data(); + void exitStatus(); + void loopBackTest(); + void readTimeoutAndThenCrash(); + void waitForFinished(); + void deadWhileReading(); + void restartProcessDeadlock(); + void closeWriteChannel(); + void closeReadChannel(); + void openModes(); + void emitReadyReadOnlyWhenNewDataArrives(); + void hardExit(); + void softExit(); + void softExitInSlots_data(); + void softExitInSlots(); + void mergedChannels(); + void forwardedChannels(); + void atEnd(); + void atEnd2(); + void processInAThread(); + void processesInMultipleThreads(); + void waitForFinishedWithTimeout(); + void waitForReadyReadInAReadyReadSlot(); + void waitForBytesWrittenInABytesWrittenSlot(); + void spaceArgsTest_data(); + void spaceArgsTest(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + void nativeArguments(); +#endif + void exitCodeTest(); + void setEnvironment_data(); + void setEnvironment(); + void setProcessEnvironment_data(); + void setProcessEnvironment(); + void systemEnvironment(); + void spaceInName(); + void lockupsInStartDetached(); + void waitForReadyReadForNonexistantProcess(); + void setStandardInputFile(); + void setStandardOutputFile_data(); + void setStandardOutputFile(); + void setStandardOutputProcess_data(); + void setStandardOutputProcess(); + void removeFileWhileProcessIsRunning(); + void fileWriterProcess(); + void detachedWorkingDirectoryAndPid(); + void switchReadChannels(); + void setWorkingDirectory(); + void startFinishStartFinish(); + void invalidProgramString_data(); + void invalidProgramString(); + void onlyOneStartedSignal(); + + // keep these at the end, since they use lots of processes and sometimes + // caused obscure failures to occur in tests that followed them (esp. on the Mac) + void failToStart(); + void failToStartWithWait(); + void failToStartWithEventLoop(); + +protected slots: + void readFromProcess(); + void exitLoopSlot(); + void restartProcess(); + void waitForReadyReadInAReadyReadSlotSlot(); + void waitForBytesWrittenInABytesWrittenSlotSlot(); + +private: + QProcess *process; + qint64 bytesAvailable; +}; + +// Testing get/set functions +void tst_QProcess::getSetCheck() +{ + QProcess obj1; + // ProcessChannelMode QProcess::readChannelMode() + // void QProcess::setReadChannelMode(ProcessChannelMode) + obj1.setReadChannelMode(QProcess::ProcessChannelMode(QProcess::SeparateChannels)); + QCOMPARE(QProcess::ProcessChannelMode(QProcess::SeparateChannels), obj1.readChannelMode()); + obj1.setReadChannelMode(QProcess::ProcessChannelMode(QProcess::MergedChannels)); + QCOMPARE(QProcess::ProcessChannelMode(QProcess::MergedChannels), obj1.readChannelMode()); + obj1.setReadChannelMode(QProcess::ProcessChannelMode(QProcess::ForwardedChannels)); + QCOMPARE(QProcess::ProcessChannelMode(QProcess::ForwardedChannels), obj1.readChannelMode()); + + // ProcessChannel QProcess::readChannel() + // void QProcess::setReadChannel(ProcessChannel) + obj1.setReadChannel(QProcess::ProcessChannel(QProcess::StandardOutput)); + QCOMPARE(QProcess::ProcessChannel(QProcess::StandardOutput), obj1.readChannel()); + obj1.setReadChannel(QProcess::ProcessChannel(QProcess::StandardError)); + QCOMPARE(QProcess::ProcessChannel(QProcess::StandardError), obj1.readChannel()); +} + +tst_QProcess::tst_QProcess() +{ +} + +tst_QProcess::~tst_QProcess() +{ +} + +void tst_QProcess::init() +{ +#ifdef Q_OS_SYMBIAN + QString dirStr = QString::fromLatin1("c:\\logs"); + QDir dir; + if (!dir.exists(dirStr)) + dir.mkpath(dirStr); +#endif +} + +void tst_QProcess::cleanup() +{ +} + +//----------------------------------------------------------------------------- +void tst_QProcess::constructing() +{ + QProcess process; + QCOMPARE(process.readChannel(), QProcess::StandardOutput); + QCOMPARE(process.workingDirectory(), QString()); + QCOMPARE(process.environment(), QStringList()); + QCOMPARE(process.error(), QProcess::UnknownError); + QCOMPARE(process.state(), QProcess::NotRunning); + QCOMPARE(process.pid(), Q_PID(0)); + QCOMPARE(process.readAllStandardOutput(), QByteArray()); + QCOMPARE(process.readAllStandardError(), QByteArray()); + QCOMPARE(process.canReadLine(), false); + + // QIODevice + QCOMPARE(process.openMode(), QIODevice::NotOpen); + QVERIFY(!process.isOpen()); + QVERIFY(!process.isReadable()); + QVERIFY(!process.isWritable()); + QVERIFY(process.isSequential()); + QCOMPARE(process.pos(), qlonglong(0)); + QCOMPARE(process.size(), qlonglong(0)); + QVERIFY(process.atEnd()); + QCOMPARE(process.bytesAvailable(), qlonglong(0)); + QCOMPARE(process.bytesToWrite(), qlonglong(0)); + QVERIFY(!process.errorString().isEmpty()); + + char c; + QCOMPARE(process.read(&c, 1), qlonglong(-1)); + QCOMPARE(process.write(&c, 1), qlonglong(-1)); + + QProcess proc2; +} + +void tst_QProcess::simpleStart() +{ + qRegisterMetaType<QProcess::ProcessState>("QProcess::ProcessState"); + + process = new QProcess; + QSignalSpy spy(process, SIGNAL(stateChanged(QProcess::ProcessState))); + connect(process, SIGNAL(readyRead()), this, SLOT(readFromProcess())); + + /* valgrind dislike SUID binaries(those that have the `s'-flag set), which + * makes it fail to start the process. For this reason utilities like `ping' won't + * start, when the auto test is run through `valgrind'. */ + process->start("testProcessNormal/testProcessNormal"); + if (process->state() != QProcess::Starting) + QCOMPARE(process->state(), QProcess::Running); + QVERIFY2(process->waitForStarted(5000), qPrintable(process->errorString())); + QCOMPARE(process->state(), QProcess::Running); +#if defined(Q_OS_WINCE) + // Note: This actually seems incorrect, it will only exit the while loop when finishing fails + while (process->waitForFinished(5000)) + { } +#elif defined(Q_OS_SYMBIAN) + QVERIFY(process->waitForFinished(5000)); +#else + while (process->waitForReadyRead(5000)) + { } +#endif + QCOMPARE(int(process->state()), int(QProcess::NotRunning)); + + delete process; + process = 0; + + QCOMPARE(spy.count(), 3); + QCOMPARE(qVariantValue<QProcess::ProcessState>(spy.at(0).at(0)), QProcess::Starting); + QCOMPARE(qVariantValue<QProcess::ProcessState>(spy.at(1).at(0)), QProcess::Running); + QCOMPARE(qVariantValue<QProcess::ProcessState>(spy.at(2).at(0)), QProcess::NotRunning); +} +//----------------------------------------------------------------------------- +void tst_QProcess::execute() +{ + QCOMPARE(QProcess::execute("testProcessNormal/testProcessNormal", + QStringList() << "arg1" << "arg2"), 0); + QCOMPARE(QProcess::execute("nonexistingexe"), -2); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::startDetached() +{ + QProcess proc; + QVERIFY(proc.startDetached("testProcessNormal/testProcessNormal", + QStringList() << "arg1" << "arg2")); + QCOMPARE(QProcess::startDetached("nonexistingexe"), false); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::readFromProcess() +{ + int lines = 0; + while (process->canReadLine()) { + ++lines; + QByteArray line = process->readLine(); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::crashTest() +{ + qRegisterMetaType<QProcess::ProcessState>("QProcess::ProcessState"); +#ifdef Q_OS_WIN + QSKIP("This test opens a crash dialog on Windows", SkipSingle); +#endif + process = new QProcess; + QSignalSpy stateSpy(process, SIGNAL(stateChanged(QProcess::ProcessState))); + process->start("testProcessCrash/testProcessCrash"); + QVERIFY(process->waitForStarted(5000)); + + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ProcessError>("QProcess::ExitStatus"); + + QSignalSpy spy(process, SIGNAL(error(QProcess::ProcessError))); + QSignalSpy spy2(process, SIGNAL(finished(int, QProcess::ExitStatus))); + + QVERIFY(process->waitForFinished(30000)); + + QCOMPARE(spy.count(), 1); + QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy.at(0).at(0).constData()), QProcess::Crashed); + + QCOMPARE(spy2.count(), 1); + QCOMPARE(*static_cast<const QProcess::ExitStatus *>(spy2.at(0).at(1).constData()), QProcess::CrashExit); + + QCOMPARE(process->exitStatus(), QProcess::CrashExit); + + delete process; + process = 0; + + QCOMPARE(stateSpy.count(), 3); + QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(0).at(0)), QProcess::Starting); + QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(1).at(0)), QProcess::Running); + QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(2).at(0)), QProcess::NotRunning); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::crashTest2() +{ +#ifdef Q_OS_WIN + QSKIP("This test opens a crash dialog on Windows", SkipSingle); +#endif + process = new QProcess; + process->start("testProcessCrash/testProcessCrash"); + QVERIFY(process->waitForStarted(5000)); + + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ProcessError>("QProcess::ExitStatus"); + + QSignalSpy spy(process, SIGNAL(error(QProcess::ProcessError))); + QSignalSpy spy2(process, SIGNAL(finished(int, QProcess::ExitStatus))); + + QObject::connect(process, SIGNAL(finished(int)), this, SLOT(exitLoopSlot())); + + QTestEventLoop::instance().enterLoop(30); + if (QTestEventLoop::instance().timeout()) + QFAIL("Failed to detect crash : operation timed out"); + + QCOMPARE(spy.count(), 1); + QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy.at(0).at(0).constData()), QProcess::Crashed); + + QCOMPARE(spy2.count(), 1); + QCOMPARE(*static_cast<const QProcess::ExitStatus *>(spy2.at(0).at(1).constData()), QProcess::CrashExit); + + QCOMPARE(process->exitStatus(), QProcess::CrashExit); + + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::echoTest_data() +{ + QTest::addColumn<QByteArray>("input"); + + QTest::newRow("1") << QByteArray("H"); + QTest::newRow("2") << QByteArray("He"); + QTest::newRow("3") << QByteArray("Hel"); + QTest::newRow("4") << QByteArray("Hell"); + QTest::newRow("5") << QByteArray("Hello"); + QTest::newRow("100 bytes") << QByteArray(100, '@'); + QTest::newRow("1000 bytes") << QByteArray(1000, '@'); + QTest::newRow("10000 bytes") << QByteArray(10000, '@'); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::echoTest() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QFETCH(QByteArray, input); + + process = new QProcess; + connect(process, SIGNAL(readyRead()), this, SLOT(exitLoopSlot())); + +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif + QVERIFY(process->waitForStarted(5000)); + + process->write(input); + + QTime stopWatch; + stopWatch.start(); + do { + QVERIFY(process->isOpen()); + QTestEventLoop::instance().enterLoop(2); + } while (stopWatch.elapsed() < 60000 && process->bytesAvailable() < input.size()); + if (stopWatch.elapsed() >= 60000) + QFAIL("Timed out"); + + QByteArray message = process->readAll(); + QCOMPARE(message.size(), input.size()); + + char *c1 = message.data(); + char *c2 = input.data(); + while (*c1 && *c2) { + if (*c1 != *c2) + QCOMPARE(*c1, *c2); + ++c1; + ++c2; + } + QCOMPARE(*c1, *c2); + + process->write("", 1); + + QVERIFY(process->waitForFinished(5000)); + + + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::exitLoopSlot() +{ + QTestEventLoop::instance().exitLoop(); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::echoTest2() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + process = new QProcess; + connect(process, SIGNAL(readyRead()), this, SLOT(exitLoopSlot())); + +#ifdef Q_OS_MAC + process->start("testProcessEcho2/testProcessEcho2.app"); +#else + process->start("testProcessEcho2/testProcessEcho2"); +#endif + QVERIFY(process->waitForStarted(5000)); + QVERIFY(!process->waitForReadyRead(250)); + QCOMPARE(process->error(), QProcess::Timedout); + + process->write("Hello"); + QSignalSpy spy1(process, SIGNAL(readyReadStandardOutput())); + QSignalSpy spy2(process, SIGNAL(readyReadStandardError())); + + QTime stopWatch; + stopWatch.start(); + forever { + QTestEventLoop::instance().enterLoop(1); + if (stopWatch.elapsed() >= 30000) + QFAIL("Timed out"); + process->setReadChannel(QProcess::StandardOutput); + qint64 baso = process->bytesAvailable(); + + process->setReadChannel(QProcess::StandardError); + qint64 base = process->bytesAvailable(); + if (baso == 5 && base == 5) + break; + } + + QVERIFY(spy1.count() > 0); + QVERIFY(spy2.count() > 0); + + QCOMPARE(process->readAllStandardOutput(), QByteArray("Hello")); + QCOMPARE(process->readAllStandardError(), QByteArray("Hello")); + + process->write("", 1); + QVERIFY(process->waitForFinished(5000)); + + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::echoTest_performance() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess process; +#ifdef Q_OS_MAC + process.start("testProcessLoopback/testProcessLoopback.app"); +#else + process.start("testProcessLoopback/testProcessLoopback"); +#endif + + QByteArray array; + array.resize(1024 * 1024); + for (int j = 0; j < array.size(); ++j) + array[j] = 'a' + (j % 20); + + QVERIFY(process.waitForStarted()); + + QTime stopWatch; + stopWatch.start(); + + qint64 totalBytes = 0; + QByteArray dump; + QSignalSpy readyReadSpy(&process, SIGNAL(readyRead())); + while (stopWatch.elapsed() < 2000) { + process.write(array); + while (process.bytesToWrite() > 0) { + int readCount = readyReadSpy.count(); + QVERIFY(process.waitForBytesWritten(5000)); + if (readyReadSpy.count() == readCount) + QVERIFY(process.waitForReadyRead(5000)); + } + + while (process.bytesAvailable() < array.size()) + QVERIFY2(process.waitForReadyRead(5000), qPrintable(process.errorString())); + dump = process.readAll(); + totalBytes += dump.size(); + } + + qDebug() << "Elapsed time:" << stopWatch.elapsed() << "ms;" + << "transfer rate:" << totalBytes / (1048.576) / stopWatch.elapsed() + << "MB/s"; + + for (int j = 0; j < array.size(); ++j) + QCOMPARE(char(dump.at(j)), char('a' + (j % 20))); + + process.closeWriteChannel(); + QVERIFY(process.waitForFinished()); +} + +#if defined Q_OS_WIN +//----------------------------------------------------------------------------- +void tst_QProcess::echoTestGui() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess process; + + process.start("testProcessEchoGui/testProcessEchoGui"); + + + process.write("Hello"); + process.write("q"); + + QVERIFY(process.waitForFinished(50000)); + + QCOMPARE(process.readAllStandardOutput(), QByteArray("Hello")); + QCOMPARE(process.readAllStandardError(), QByteArray("Hello")); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::batFiles_data() +{ + QTest::addColumn<QString>("batFile"); + QTest::addColumn<QByteArray>("output"); + + QTest::newRow("simple") << QString::fromLatin1("testBatFiles/simple.bat") << QByteArray("Hello"); + QTest::newRow("with space") << QString::fromLatin1("testBatFiles/with space.bat") << QByteArray("Hello"); +} + +void tst_QProcess::batFiles() +{ +#if defined(Q_OS_WINCE) + QSKIP("Batch files are not supported on Windows CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Batch files are not supported on Symbian", SkipAll); +#endif + QFETCH(QString, batFile); + QFETCH(QByteArray, output); + + QProcess proc; + + proc.start(batFile, QStringList()); + + QVERIFY(proc.waitForFinished(5000)); + + QVERIFY(proc.bytesAvailable() > 0); + + QVERIFY(proc.readAll().startsWith(output)); +} + +#endif + +//----------------------------------------------------------------------------- +void tst_QProcess::exitStatus_data() +{ + QTest::addColumn<QStringList>("processList"); + QTest::addColumn<QList<QProcess::ExitStatus> >("exitStatus"); + + QTest::newRow("normal") << (QStringList() << "testProcessNormal/testProcessNormal") + << (QList<QProcess::ExitStatus>() << QProcess::NormalExit); + QTest::newRow("crash") << (QStringList() << "testProcessCrash/testProcessCrash") + << (QList<QProcess::ExitStatus>() << QProcess::CrashExit); + + QTest::newRow("normal-crash") << (QStringList() + << "testProcessNormal/testProcessNormal" + << "testProcessCrash/testProcessCrash") + << (QList<QProcess::ExitStatus>() + << QProcess::NormalExit + << QProcess::CrashExit); + QTest::newRow("crash-normal") << (QStringList() + << "testProcessCrash/testProcessCrash" + << "testProcessNormal/testProcessNormal") + << (QList<QProcess::ExitStatus>() + << QProcess::CrashExit + << QProcess::NormalExit); +} + +void tst_QProcess::exitStatus() +{ + process = new QProcess; + QFETCH(QStringList, processList); + QFETCH(QList<QProcess::ExitStatus>, exitStatus); + +#ifdef Q_OS_WIN + if (exitStatus.contains(QProcess::CrashExit)) + QSKIP("This test opens a crash dialog on Windows", SkipSingle); +#endif + + QCOMPARE(exitStatus.count(), processList.count()); + for (int i = 0; i < processList.count(); ++i) { + process->start(processList.at(i)); + QVERIFY(process->waitForStarted(5000)); + QVERIFY(process->waitForFinished(30000)); + + QCOMPARE(process->exitStatus(), exitStatus.at(i)); + } + + process->deleteLater(); + process = 0; +} +//----------------------------------------------------------------------------- +void tst_QProcess::loopBackTest() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + process = new QProcess; +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif + QVERIFY(process->waitForStarted(5000)); + + for (int i = 0; i < 100; ++i) { + process->write("Hello"); + do { + QVERIFY(process->waitForReadyRead(5000)); + } while (process->bytesAvailable() < 5); + QCOMPARE(process->readAll(), QByteArray("Hello")); + } + + process->write("", 1); + QVERIFY(process->waitForFinished(5000)); + + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::readTimeoutAndThenCrash() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + process = new QProcess; +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif + if (process->state() != QProcess::Starting) + QCOMPARE(process->state(), QProcess::Running); + + QVERIFY(process->waitForStarted(5000)); + QCOMPARE(process->state(), QProcess::Running); + + QVERIFY(!process->waitForReadyRead(5000)); + QCOMPARE(process->error(), QProcess::Timedout); + + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + QSignalSpy spy(process, SIGNAL(error(QProcess::ProcessError))); + + process->kill(); + + QVERIFY(process->waitForFinished(5000)); + QCOMPARE(process->state(), QProcess::NotRunning); + + QCOMPARE(spy.count(), 1); + QCOMPARE(*static_cast<const QProcess::ProcessError *>(spy.at(0).at(0).constData()), QProcess::Crashed); + + delete process; + process = 0; +} + +void tst_QProcess::waitForFinished() +{ + QProcess process; + +#ifdef Q_OS_MAC + process.start("testProcessOutput/testProcessOutput.app"); +#else + process.start("testProcessOutput/testProcessOutput"); +#endif + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QVERIFY(process.waitForFinished(5000)); +#else + QVERIFY(process.waitForFinished(30000)); +#endif + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + +#if defined(Q_OS_SYMBIAN) + // Symbian test outputs to a file, so check that + FILE* file = fopen("c:\\logs\\qprocess_output_test.txt","r"); + int retval = 0; + int count = 0; + while((int)(retval = fgetc(file) )!= EOF) + if (retval == '\n') + count++; + fclose(file); + QCOMPARE(count, 200); +#else +# if defined (Q_OS_WINCE) + QEXPECT_FAIL("", "Reading and writing to a process is not supported on Qt/CE", Continue); +# endif + QString output = process.readAll(); + QCOMPARE(output.count("\n"), 10*1024); +#endif + + process.start("blurdybloop"); + QVERIFY(!process.waitForFinished()); + QCOMPARE(process.error(), QProcess::FailedToStart); +} + + +void tst_QProcess::deadWhileReading() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess process; + +#ifdef Q_OS_MAC + process.start("testProcessDeadWhileReading/testProcessDeadWhileReading.app"); +#else + process.start("testProcessDeadWhileReading/testProcessDeadWhileReading"); +#endif + + QString output; + + QVERIFY(process.waitForStarted(5000)); + while (process.waitForReadyRead(5000)) + output += process.readAll(); + + QCOMPARE(output.count("\n"), 10*1024); + process.waitForFinished(); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::restartProcessDeadlock() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + // The purpose of this test is to detect whether restarting a + // process in the finished() connected slot causes a deadlock + // because of the way QProcessManager uses its locks. + QProcess proc; + process = &proc; + connect(process, SIGNAL(finished(int)), this, SLOT(restartProcess())); + +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif + + QCOMPARE(process->write("", 1), qlonglong(1)); + QVERIFY(process->waitForFinished(5000)); + + process->disconnect(SIGNAL(finished(int))); + + QCOMPARE(process->write("", 1), qlonglong(1)); + QVERIFY(process->waitForFinished(5000)); +} + +void tst_QProcess::restartProcess() +{ +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif +} + +//----------------------------------------------------------------------------- +void tst_QProcess::closeWriteChannel() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess more; + more.start("testProcessEOF/testProcessEOF"); + + QVERIFY(more.waitForStarted(5000)); + QVERIFY(!more.waitForReadyRead(250)); + QCOMPARE(more.error(), QProcess::Timedout); + + QVERIFY(more.write("Data to read") != -1); + + QVERIFY(!more.waitForReadyRead(250)); + QCOMPARE(more.error(), QProcess::Timedout); + + more.closeWriteChannel(); + + QVERIFY(more.waitForReadyRead(5000)); + QVERIFY(more.readAll().startsWith("Data to read")); + + if (more.state() == QProcess::Running) + more.write("q"); + QVERIFY(more.waitForFinished(5000)); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::closeReadChannel() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + for (int i = 0; i < 10; ++i) { + QProcess::ProcessChannel channel1 = QProcess::StandardOutput; + QProcess::ProcessChannel channel2 = QProcess::StandardError; + + QProcess proc; +#ifdef Q_OS_MAC + proc.start("testProcessEcho2/testProcessEcho2.app"); +#else + proc.start("testProcessEcho2/testProcessEcho2"); +#endif + QVERIFY(proc.waitForStarted(5000)); + proc.closeReadChannel(i&1 ? channel2 : channel1); + proc.setReadChannel(i&1 ? channel2 : channel1); + proc.write("Data"); + + QVERIFY(!proc.waitForReadyRead(5000)); + QVERIFY(proc.readAll().isEmpty()); + + proc.setReadChannel(i&1 ? channel1 : channel2); + + while (proc.bytesAvailable() < 4 && proc.waitForReadyRead(5000)) + { } + + QCOMPARE(proc.readAll(), QByteArray("Data")); + + proc.write("", 1); + QVERIFY(proc.waitForFinished(5000)); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::openModes() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess proc; + QVERIFY(!proc.isOpen()); + QVERIFY(proc.openMode() == QProcess::NotOpen); +#ifdef Q_OS_MAC + proc.start("testProcessEcho3/testProcessEcho3.app"); +#else + proc.start("testProcessEcho3/testProcessEcho3"); +#endif + QVERIFY(proc.waitForStarted(5000)); + QVERIFY(proc.isOpen()); + QVERIFY(proc.openMode() == QProcess::ReadWrite); + QVERIFY(proc.isReadable()); + QVERIFY(proc.isWritable()); + + proc.write("Data"); + + proc.closeWriteChannel(); + + QVERIFY(proc.isWritable()); + QVERIFY(proc.openMode() == QProcess::ReadWrite); + + while (proc.bytesAvailable() < 4 && proc.waitForReadyRead(5000)) + { } + + QCOMPARE(proc.readAll().constData(), QByteArray("Data").constData()); + + proc.closeReadChannel(QProcess::StandardOutput); + + QVERIFY(proc.openMode() == QProcess::ReadWrite); + QVERIFY(proc.isReadable()); + + proc.closeReadChannel(QProcess::StandardError); + + QVERIFY(proc.openMode() == QProcess::ReadWrite); + QVERIFY(proc.isReadable()); + + proc.close(); + QVERIFY(!proc.isOpen()); + QVERIFY(!proc.isReadable()); + QVERIFY(!proc.isWritable()); + QCOMPARE(proc.state(), QProcess::NotRunning); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::emitReadyReadOnlyWhenNewDataArrives() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess proc; + connect(&proc, SIGNAL(readyRead()), this, SLOT(exitLoopSlot())); + QSignalSpy spy(&proc, SIGNAL(readyRead())); + +#ifdef Q_OS_MAC + proc.start("testProcessEcho/testProcessEcho.app"); +#else + proc.start("testProcessEcho/testProcessEcho"); +#endif + + QCOMPARE(spy.count(), 0); + + proc.write("A"); + + QTestEventLoop::instance().enterLoop(5); + if (QTestEventLoop::instance().timeout()) + QFAIL("Operation timed out"); + + QCOMPARE(spy.count(), 1); + + QTestEventLoop::instance().enterLoop(1); + QVERIFY(QTestEventLoop::instance().timeout()); + QVERIFY(!proc.waitForReadyRead(250)); + + QObject::disconnect(&proc, SIGNAL(readyRead()), 0, 0); + proc.write("B"); + QVERIFY(proc.waitForReadyRead(5000)); + + proc.write("", 1); + QVERIFY(proc.waitForFinished(5000)); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::hardExit() +{ +#if defined(Q_OS_SYMBIAN) + QSKIP("Killing started processes is not supported on Qt/Symbian due platform security", SkipAll); +#endif + QProcess proc; + +#if defined(Q_OS_MAC) + proc.start("testProcessEcho/testProcessEcho.app"); +#elif defined(Q_OS_WINCE) + proc.start("testSoftExit/testSoftExit"); +#else + proc.start("testProcessEcho/testProcessEcho"); +#endif + +#ifndef Q_OS_WINCE + QVERIFY(proc.waitForStarted(5000)); +#else + QVERIFY(proc.waitForStarted(10000)); +#endif + + proc.kill(); + + QVERIFY(proc.waitForFinished(5000)); + QCOMPARE(int(proc.state()), int(QProcess::NotRunning)); + QCOMPARE(int(proc.error()), int(QProcess::Crashed)); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::softExit() +{ +#if defined(Q_OS_SYMBIAN) + QSKIP("Terminating started processes is not supported on Qt/Symbian due platform security", SkipAll); +#endif + QProcess proc; + + proc.start("testSoftExit/testSoftExit"); + + QVERIFY(proc.waitForStarted(10000)); +#if !defined(Q_OS_WINCE) + QVERIFY(proc.waitForReadyRead(10000)); +#endif + + proc.terminate(); + + QVERIFY(proc.waitForFinished(10000)); + QCOMPARE(int(proc.state()), int(QProcess::NotRunning)); + QCOMPARE(int(proc.error()), int(QProcess::UnknownError)); +} + +class SoftExitProcess : public QProcess +{ + Q_OBJECT +public: + bool waitedForFinished; + + SoftExitProcess(int n) : waitedForFinished(false), n(n), killing(false) + { + connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(finishedSlot(int, QProcess::ExitStatus))); + + switch (n) { + case 0: + setReadChannelMode(QProcess::MergedChannels); + connect(this, SIGNAL(readyRead()), this, SLOT(terminateSlot())); + break; + case 1: + connect(this, SIGNAL(readyReadStandardOutput()), + this, SLOT(terminateSlot())); + break; + case 2: + connect(this, SIGNAL(readyReadStandardError()), + this, SLOT(terminateSlot())); + break; + case 3: + connect(this, SIGNAL(started()), + this, SLOT(terminateSlot())); + break; + case 4: + default: + connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), + this, SLOT(terminateSlot())); + break; + } + } + +public slots: + void terminateSlot() + { + if (killing || (n == 4 && state() != Running)) { + // Don't try to kill the process before it is running - that can + // be hazardous, as the actual child process might not be running + // yet. Also, don't kill it "recursively". + return; + } + killing = true; + readAll(); + terminate(); + if ((waitedForFinished = waitForFinished(5000)) == false) { + kill(); + if (state() != NotRunning) + waitedForFinished = waitForFinished(5000); + } + } + + void finishedSlot(int, QProcess::ExitStatus) + { + waitedForFinished = true; + } + +private: + int n; + bool killing; +}; + +//----------------------------------------------------------------------------- +void tst_QProcess::softExitInSlots_data() +{ + QTest::addColumn<QString>("appName"); + +#ifdef Q_OS_MAC + QTest::newRow("gui app") << "testGuiProcess/testGuiProcess.app"; +#else + QTest::newRow("gui app") << "testGuiProcess/testGuiProcess"; +#endif +#ifdef Q_OS_MAC + QTest::newRow("console app") << "testProcessEcho2/testProcessEcho2.app"; +#else + QTest::newRow("console app") << "testProcessEcho2/testProcessEcho2"; +#endif +} + +//----------------------------------------------------------------------------- +void tst_QProcess::softExitInSlots() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QFETCH(QString, appName); + + for (int i = 0; i < 5; ++i) { + SoftExitProcess proc(i); + proc.start(appName); + proc.write("OLEBOLE", 8); // include the \0 + QTestEventLoop::instance().enterLoop(10); + QCOMPARE(proc.state(), QProcess::NotRunning); + QVERIFY(proc.waitedForFinished); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::mergedChannels() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess process; + process.setReadChannelMode(QProcess::MergedChannels); + QCOMPARE(process.readChannelMode(), QProcess::MergedChannels); + +#ifdef Q_OS_MAC + process.start("testProcessEcho2/testProcessEcho2.app"); +#else + process.start("testProcessEcho2/testProcessEcho2"); +#endif + + QVERIFY(process.waitForStarted(5000)); + + for (int i = 0; i < 100; ++i) { + QCOMPARE(process.write("abc"), qlonglong(3)); + while (process.bytesAvailable() < 6) + QVERIFY(process.waitForReadyRead(5000)); + QCOMPARE(process.readAll(), QByteArray("aabbcc")); + } + + process.closeWriteChannel(); + QVERIFY(process.waitForFinished(5000)); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::forwardedChannels() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess process; + process.setReadChannelMode(QProcess::ForwardedChannels); + QCOMPARE(process.readChannelMode(), QProcess::ForwardedChannels); + +#ifdef Q_OS_MAC + process.start("testProcessEcho2/testProcessEcho2.app"); +#else + process.start("testProcessEcho2/testProcessEcho2"); +#endif + + QVERIFY(process.waitForStarted(5000)); + QCOMPARE(process.write("forwarded\n"), qlonglong(10)); + QVERIFY(!process.waitForReadyRead(250)); + QCOMPARE(process.bytesAvailable(), qlonglong(0)); + + process.closeWriteChannel(); + QVERIFY(process.waitForFinished(5000)); +} + + +//----------------------------------------------------------------------------- +void tst_QProcess::atEnd() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess process; + +#ifdef Q_OS_MAC + process.start("testProcessEcho/testProcessEcho.app"); +#else + process.start("testProcessEcho/testProcessEcho"); +#endif + process.write("abcdefgh\n"); + + while (process.bytesAvailable() < 8) + QVERIFY(process.waitForReadyRead(5000)); + + QTextStream stream(&process); + QVERIFY(!stream.atEnd()); + QString tmp = stream.readLine(); + QVERIFY(stream.atEnd()); + QCOMPARE(tmp, QString::fromLatin1("abcdefgh")); + + process.write("", 1); + QVERIFY(process.waitForFinished(5000)); +} + +class TestThread : public QThread +{ + Q_OBJECT +public: + inline int code() + { + return exitCode; + } + +#if defined(Q_OS_SYMBIAN) + int serial; +#endif + +protected: + inline void run() + { + exitCode = 90210; + + QProcess process; + connect(&process, SIGNAL(finished(int)), this, SLOT(catchExitCode(int)), + Qt::DirectConnection); + +#ifdef Q_OS_MAC + process.start("testProcessEcho/testProcessEcho.app"); +#elif defined(Q_OS_SYMBIAN) && defined(Q_CC_NOKIAX86) + // WINSCW builds in Symbian do not allow multiple processes to load Qt libraries, + // so use just a simple process instead of testDetached. + process.start("testProcessNormal"); +#elif defined(Q_OS_SYMBIAN) + // testDetached used because it does something, but doesn't take too long. + QFile infoFile(QString("c:\\logs\\detinfo%1").arg(serial)); + QStringList args; + args << infoFile.fileName(); + process.start("testDetached", args); +#else + process.start("testProcessEcho/testProcessEcho"); +#endif + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QCOMPARE(process.write("abc\0", 4), qint64(4)); +#endif + exitCode = exec(); + } + +protected slots: + inline void catchExitCode(int exitCode) + { + this->exitCode = exitCode; + exit(exitCode); + } + +private: + int exitCode; +}; + +//----------------------------------------------------------------------------- +void tst_QProcess::processInAThread() +{ + for (int i = 0; i < 10; ++i) { + TestThread thread; + thread.start(); + QVERIFY(thread.wait(10000)); + QCOMPARE(thread.code(), 0); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::processesInMultipleThreads() +{ +#if defined(Q_OS_SYMBIAN) + int serialCounter = 0; +#endif + + for (int i = 0; i < 10; ++i) { + TestThread thread1; + TestThread thread2; + TestThread thread3; + +#if defined(Q_OS_SYMBIAN) + thread1.serial = serialCounter++; + thread2.serial = serialCounter++; + thread3.serial = serialCounter++; +#endif + thread1.start(); + thread2.start(); + thread3.start(); + + QVERIFY(thread2.wait(10000)); + QVERIFY(thread3.wait(10000)); + QVERIFY(thread1.wait(10000)); + + QCOMPARE(thread1.code(), 0); + QCOMPARE(thread2.code(), 0); + QCOMPARE(thread3.code(), 0); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::waitForFinishedWithTimeout() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif + + process = new QProcess(this); + +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#elif defined(Q_OS_SYMBIAN) + process->start("testProcessOutput"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif + +#if defined(Q_OS_SYMBIAN) + QVERIFY(process->waitForStarted(50)); + QVERIFY(!process->waitForFinished(1)); +#else + QVERIFY(process->waitForStarted(5000)); + QVERIFY(!process->waitForFinished(1)); + + process->write("", 1); +#endif + + QVERIFY(process->waitForFinished()); + + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::waitForReadyReadInAReadyReadSlot() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + process = new QProcess(this); + connect(process, SIGNAL(readyRead()), this, SLOT(waitForReadyReadInAReadyReadSlotSlot())); + connect(process, SIGNAL(finished(int)), this, SLOT(exitLoopSlot())); + bytesAvailable = 0; + +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif + QVERIFY(process->waitForStarted(5000)); + + QSignalSpy spy(process, SIGNAL(readyRead())); + process->write("foo"); + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(spy.count(), 1); + + process->disconnect(); + QVERIFY(process->waitForFinished(5000)); + QVERIFY(process->bytesAvailable() > bytesAvailable); + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::waitForReadyReadInAReadyReadSlotSlot() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + bytesAvailable = process->bytesAvailable(); + process->write("bar", 4); + QVERIFY(process->waitForReadyRead(5000)); + QTestEventLoop::instance().exitLoop(); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::waitForBytesWrittenInABytesWrittenSlot() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + process = new QProcess(this); + connect(process, SIGNAL(bytesWritten(qint64)), this, SLOT(waitForBytesWrittenInABytesWrittenSlotSlot())); + bytesAvailable = 0; + +#ifdef Q_OS_MAC + process->start("testProcessEcho/testProcessEcho.app"); +#else + process->start("testProcessEcho/testProcessEcho"); +#endif + QVERIFY(process->waitForStarted(5000)); + + qRegisterMetaType<qint64>("qint64"); + QSignalSpy spy(process, SIGNAL(bytesWritten(qint64))); + process->write("f"); + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(spy.count(), 1); + process->write("", 1); + process->disconnect(); + QVERIFY(process->waitForFinished()); + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::waitForBytesWrittenInABytesWrittenSlotSlot() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + process->write("b"); + QVERIFY(process->waitForBytesWritten(5000)); + QTestEventLoop::instance().exitLoop(); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::spaceArgsTest_data() +{ + QTest::addColumn<QStringList>("args"); + QTest::addColumn<QString>("stringArgs"); + + // arg1 | arg2 + QTest::newRow("arg1 arg2") << (QStringList() << QString::fromLatin1("arg1") << QString::fromLatin1("arg2")) + << QString::fromLatin1("arg1 arg2"); + // "arg1" | ar "g2 + QTest::newRow("\"\"\"\"arg1\"\"\"\" \"ar \"\"\"g2\"") << (QStringList() << QString::fromLatin1("\"arg1\"") << QString::fromLatin1("ar \"g2")) + << QString::fromLatin1("\"\"\"\"arg1\"\"\"\" \"ar \"\"\"g2\""); + // ar g1 | a rg 2 + QTest::newRow("\"ar g1\" \"a rg 2\"") << (QStringList() << QString::fromLatin1("ar g1") << QString::fromLatin1("a rg 2")) + << QString::fromLatin1("\"ar g1\" \"a rg 2\""); + // -lar g1 | -l"ar g2" + QTest::newRow("\"-lar g1\" \"-l\"\"\"ar g2\"\"\"\"") << (QStringList() << QString::fromLatin1("-lar g1") << QString::fromLatin1("-l\"ar g2\"")) + << QString::fromLatin1("\"-lar g1\" \"-l\"\"\"ar g2\"\"\"\""); + // ar"g1 + QTest::newRow("ar\"\"\"\"g1") << (QStringList() << QString::fromLatin1("ar\"g1")) + << QString::fromLatin1("ar\"\"\"\"g1"); + // ar/g1 + QTest::newRow("ar\\g1") << (QStringList() << QString::fromLatin1("ar\\g1")) + << QString::fromLatin1("ar\\g1"); + // ar\g"1 + QTest::newRow("ar\\g\"\"\"\"1") << (QStringList() << QString::fromLatin1("ar\\g\"1")) + << QString::fromLatin1("ar\\g\"\"\"\"1"); + // arg\"1 + QTest::newRow("arg\\\"\"\"1") << (QStringList() << QString::fromLatin1("arg\\\"1")) + << QString::fromLatin1("arg\\\"\"\"1"); + // """" + QTest::newRow("\"\"\"\"\"\"\"\"\"\"\"\"") << (QStringList() << QString::fromLatin1("\"\"\"\"")) + << QString::fromLatin1("\"\"\"\"\"\"\"\"\"\"\"\""); + // """" | "" "" + QTest::newRow("\"\"\"\"\"\"\"\"\"\"\"\" \"\"\"\"\"\"\" \"\"\"\"\"\"\"") << (QStringList() << QString::fromLatin1("\"\"\"\"") << QString::fromLatin1("\"\" \"\"")) + << QString::fromLatin1("\"\"\"\"\"\"\"\"\"\"\"\" \"\"\"\"\"\"\" \"\"\"\"\"\"\""); + // "" "" + QTest::newRow("\"\"\"\"\"\"\" \"\" \"\"\"\"\"\"\" (bogus double quotes)") << (QStringList() << QString::fromLatin1("\"\" \"\"")) + << QString::fromLatin1("\"\"\"\"\"\"\" \"\" \"\"\"\"\"\"\""); + // "" "" + QTest::newRow(" \"\"\"\"\"\"\" \"\" \"\"\"\"\"\"\" (bogus double quotes)") << (QStringList() << QString::fromLatin1("\"\" \"\"")) + << QString::fromLatin1(" \"\"\"\"\"\"\" \"\" \"\"\"\"\"\"\" "); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::spaceArgsTest() +{ + QFETCH(QStringList, args); + QFETCH(QString, stringArgs); + + QStringList programs; + programs << QString::fromLatin1("testProcessSpacesArgs/nospace") +#if defined(Q_OS_SYMBIAN) + ; // Symbian toolchain doesn't like exes with spaces in the name +#else + << QString::fromLatin1("testProcessSpacesArgs/one space") + << QString::fromLatin1("testProcessSpacesArgs/two space s"); +#endif + + process = new QProcess(this); + + for (int i = 0; i < programs.size(); ++i) { + QString program = programs.at(i); + process->start(program, args); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QVERIFY(process->waitForStarted(5000)); + QVERIFY(process->waitForFinished(5000)); +#else + QVERIFY(process->waitForStarted(10000)); + QVERIFY(process->waitForFinished(10000)); +#endif + +#if defined(Q_OS_SYMBIAN) + // Symbian test outputs to a file, so check that + FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","r"); + QVERIFY(file); + char buf[256]; + fgets(buf, 256, file); + fclose(file); + QStringList actual = QString::fromLatin1(buf).split("|"); +#elif !defined(Q_OS_WINCE) + QStringList actual = QString::fromLatin1(process->readAll()).split("|"); +#endif +#if !defined(Q_OS_WINCE) + QVERIFY(!actual.isEmpty()); + // not interested in the program name, it might be different. + actual.removeFirst(); + + QCOMPARE(actual, args); +#endif + + if (program.contains(" ")) + program = "\"" + program + "\""; + + if (!stringArgs.isEmpty()) + program += QString::fromLatin1(" ") + stringArgs; + + process->start(program); + + QVERIFY(process->waitForStarted(5000)); + QVERIFY(process->waitForFinished(5000)); + +#if defined(Q_OS_SYMBIAN) + // Symbian test outputs to a file, so check that + file = fopen("c:\\logs\\qprocess_args_test.txt","r"); + QVERIFY(file); + fgets(buf, 256, file); + fclose(file); + actual = QString::fromLatin1(buf).split("|"); +#elif !defined(Q_OS_WINCE) + actual = QString::fromLatin1(process->readAll()).split("|"); +#endif +#if !defined(Q_OS_WINCE) + QVERIFY(!actual.isEmpty()); + // not interested in the program name, it might be different. + actual.removeFirst(); + + QCOMPARE(actual, args); +#endif + } + + delete process; + process = 0; +} + +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + +//----------------------------------------------------------------------------- +void tst_QProcess::nativeArguments() +{ + QProcess proc; + + // This doesn't actually need special quoting, so it is pointless to use + // native arguments here, but that's not the point of this test. + proc.setNativeArguments("hello kitty, \"*\"!"); + + proc.start(QString::fromLatin1("testProcessSpacesArgs/nospace"), QStringList()); + +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QVERIFY(proc.waitForStarted(5000)); + QVERIFY(proc.waitForFinished(5000)); +#else + QVERIFY(proc.waitForStarted(10000)); + QVERIFY(proc.waitForFinished(10000)); +#endif + +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) + // Symbian test outputs to a file, so check that +# ifdef Q_OS_SYMBIAN + FILE* file = fopen("c:\\logs\\qprocess_args_test.txt","r"); +# else + FILE* file = fopen("\\temp\\qprocess_args_test.txt","r"); +# endif + QVERIFY(file); + char buf[256]; + fgets(buf, 256, file); + fclose(file); + QStringList actual = QString::fromLatin1(buf).split("|"); +#else + QStringList actual = QString::fromLatin1(proc.readAll()).split("|"); +#endif + QVERIFY(!actual.isEmpty()); + // not interested in the program name, it might be different. + actual.removeFirst(); + QStringList expected; +#if defined(Q_OS_WINCE) + expected << "hello" << "kitty," << "\"*\"!"; // Weird, weird ... +#else + expected << "hello" << "kitty," << "*!"; +#endif + QCOMPARE(actual, expected); +} + +#endif + +//----------------------------------------------------------------------------- +void tst_QProcess::exitCodeTest() +{ +#if defined(Q_OS_SYMBIAN) + // Kernel will run out of process handles on some hw, as there is some + // delay before they are recycled, so limit the amount of processes. + for (int i = 0; i < 50; ++i) { +#else + for (int i = 0; i < 255; ++i) { +#endif + QProcess process; + process.start("testExitCodes/testExitCodes " + QString::number(i)); + QVERIFY(process.waitForFinished(5000)); + QCOMPARE(process.exitCode(), i); + QCOMPARE(process.error(), QProcess::UnknownError); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::failToStart() +{ + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); + qRegisterMetaType<QProcess::ProcessState>("QProcess::ProcessState"); + + QProcess process; + QSignalSpy stateSpy(&process, SIGNAL(stateChanged(QProcess::ProcessState))); + QSignalSpy errorSpy(&process, SIGNAL(error(QProcess::ProcessError))); + QSignalSpy finishedSpy(&process, SIGNAL(finished(int))); + QSignalSpy finishedSpy2(&process, SIGNAL(finished(int, QProcess::ExitStatus))); + +// Mac OS X and HP-UX have a really low default process limit (~100), so spawning +// to many processes here will cause test failures later on. +#if defined Q_OS_HPUX + const int attempts = 15; +#elif defined Q_OS_MAC + const int attempts = 15; +#else + const int attempts = 50; +#endif + + for (int j = 0; j < 8; ++j) { + for (int i = 0; i < attempts; ++i) { + QCOMPARE(errorSpy.count(), j * attempts + i); + process.start("/blurp"); + + switch (j) { + case 0: + case 1: + QVERIFY(!process.waitForStarted()); + break; + case 2: + case 3: + QVERIFY(!process.waitForFinished()); + break; + case 4: + case 5: + QVERIFY(!process.waitForReadyRead()); + break; + case 6: + case 7: + default: + QVERIFY(!process.waitForBytesWritten()); + break; + } + + QCOMPARE(process.error(), QProcess::FailedToStart); + QCOMPARE(errorSpy.count(), j * attempts + i + 1); + QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(finishedSpy2.count(), 0); + + int it = j * attempts + i + 1; + + QCOMPARE(stateSpy.count(), it * 2); + QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(it * 2 - 2).at(0)), QProcess::Starting); + QCOMPARE(qVariantValue<QProcess::ProcessState>(stateSpy.at(it * 2 - 1).at(0)), QProcess::NotRunning); + } + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::failToStartWithWait() +{ + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); + + QProcess process; + QEventLoop loop; + QSignalSpy errorSpy(&process, SIGNAL(error(QProcess::ProcessError))); + QSignalSpy finishedSpy(&process, SIGNAL(finished(int))); + QSignalSpy finishedSpy2(&process, SIGNAL(finished(int, QProcess::ExitStatus))); + + for (int i = 0; i < 50; ++i) { + process.start("/blurp", QStringList() << "-v" << "-debug"); + process.waitForStarted(); + + QCOMPARE(process.error(), QProcess::FailedToStart); + QCOMPARE(errorSpy.count(), i + 1); + QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(finishedSpy2.count(), 0); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::failToStartWithEventLoop() +{ + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); + + QProcess process; + QEventLoop loop; + QSignalSpy errorSpy(&process, SIGNAL(error(QProcess::ProcessError))); + QSignalSpy finishedSpy(&process, SIGNAL(finished(int))); + QSignalSpy finishedSpy2(&process, SIGNAL(finished(int, QProcess::ExitStatus))); + + // The error signal may be emitted before start() returns + connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()), Qt::QueuedConnection); + + + for (int i = 0; i < 50; ++i) { + process.start("/blurp", QStringList() << "-v" << "-debug"); + + loop.exec(); + + QCOMPARE(process.error(), QProcess::FailedToStart); + QCOMPARE(errorSpy.count(), i + 1); + QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(finishedSpy2.count(), 0); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::removeFileWhileProcessIsRunning() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QFile file("removeFile.txt"); + QVERIFY(file.open(QFile::WriteOnly)); + + QProcess process; +#ifdef Q_OS_MAC + process.start("testProcessEcho/testProcessEcho.app"); +#else + process.start("testProcessEcho/testProcessEcho"); +#endif + + QVERIFY(process.waitForStarted(5000)); + + QVERIFY(file.remove()); + + process.write("", 1); + QVERIFY(process.waitForFinished(5000)); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::setEnvironment_data() +{ + QTest::addColumn<QString>("name"); + QTest::addColumn<QString>("value"); + + QTest::newRow("setting-empty") << "tst_QProcess" << ""; + QTest::newRow("setting") << "tst_QProcess" << "value"; + +#ifdef Q_OS_WIN + QTest::newRow("unsetting") << "PROMPT" << QString(); + QTest::newRow("overriding") << "PROMPT" << "value"; +#else + QTest::newRow("unsetting") << "PATH" << QString(); + QTest::newRow("overriding") << "PATH" << "value"; +#endif +} + +void tst_QProcess::setEnvironment() +{ +#if defined (Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("OS doesn't support environment variables", SkipAll); +#endif + + // make sure our environment variables are correct + QVERIFY(qgetenv("tst_QProcess").isEmpty()); + QVERIFY(!qgetenv("PATH").isEmpty()); +#ifdef Q_OS_WIN + QVERIFY(!qgetenv("PROMPT").isEmpty()); +#endif + + QFETCH(QString, name); + QFETCH(QString, value); + QString executable = QDir::currentPath() + "/testProcessEnvironment/testProcessEnvironment"; + + { + QProcess process; + QStringList environment = QProcess::systemEnvironment(); + if (value.isNull()) { + int pos; + QRegExp rx(name + "=.*"); +#ifdef Q_OS_WIN + rx.setCaseSensitivity(Qt::CaseInsensitive); +#endif + while ((pos = environment.indexOf(rx)) != -1) + environment.removeAt(pos); + } else { + environment.append(name + '=' + value); + } + process.setEnvironment(environment); + process.start(executable, QStringList() << name); + + QVERIFY(process.waitForFinished()); + if (value.isNull()) + QCOMPARE(process.exitCode(), 1); + else if (!value.isEmpty()) + QCOMPARE(process.exitCode(), 0); + + QCOMPARE(process.readAll(), value.toLocal8Bit()); + } + + // re-do the test but set the environment twice, to make sure + // that the latter addition overrides + // this test doesn't make sense in unsetting + if (!value.isNull()) { + QProcess process; + QStringList environment = QProcess::systemEnvironment(); + environment.prepend(name + "=This is not the right value"); + environment.append(name + '=' + value); + process.setEnvironment(environment); + process.start(executable, QStringList() << name); + + QVERIFY(process.waitForFinished()); + if (!value.isEmpty()) + QCOMPARE(process.exitCode(), 0); + + QCOMPARE(process.readAll(), value.toLocal8Bit()); + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::setProcessEnvironment_data() +{ + setEnvironment_data(); +} + +void tst_QProcess::setProcessEnvironment() +{ +#if defined (Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("OS doesn't support environment variables", SkipAll); +#endif + + // make sure our environment variables are correct + QVERIFY(qgetenv("tst_QProcess").isEmpty()); + QVERIFY(!qgetenv("PATH").isEmpty()); +#ifdef Q_OS_WIN + QVERIFY(!qgetenv("PROMPT").isEmpty()); +#endif + + QFETCH(QString, name); + QFETCH(QString, value); + QString executable = QDir::currentPath() + "/testProcessEnvironment/testProcessEnvironment"; + + { + QProcess process; + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + if (value.isNull()) + environment.remove(name); + else + environment.insert(name, value); + process.setProcessEnvironment(environment); + process.start(executable, QStringList() << name); + + QVERIFY(process.waitForFinished()); + if (value.isNull()) + QCOMPARE(process.exitCode(), 1); + else if (!value.isEmpty()) + QCOMPARE(process.exitCode(), 0); + + QCOMPARE(process.readAll(), value.toLocal8Bit()); + } +} +//----------------------------------------------------------------------------- +void tst_QProcess::systemEnvironment() +{ +#if defined (Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + // there is no concept of system variables on Windows CE as there is no console + QVERIFY(QProcess::systemEnvironment().isEmpty()); + QVERIFY(QProcessEnvironment::systemEnvironment().isEmpty()); +#else + QVERIFY(!QProcess::systemEnvironment().isEmpty()); + QVERIFY(!QProcessEnvironment::systemEnvironment().isEmpty()); + + QVERIFY(QProcessEnvironment::systemEnvironment().contains("PATH")); + QVERIFY(!QProcess::systemEnvironment().filter(QRegExp("^PATH=", Qt::CaseInsensitive)).isEmpty()); +#endif +} + +//----------------------------------------------------------------------------- +void tst_QProcess::spaceInName() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + QProcess process; + process.start("test Space In Name/testSpaceInName", QStringList()); + QVERIFY(process.waitForStarted()); + process.write("", 1); + QVERIFY(process.waitForFinished()); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::lockupsInStartDetached() +{ +#if !defined(Q_OS_SYMBIAN) + // Check that QProcess doesn't cause a lock up at this program's + // exit if a thread was started and we tried to run a program that + // doesn't exist. Before Qt 4.2, this used to lock up on Unix due + // to calling ::exit instead of ::_exit if execve failed. + + QHostInfo::lookupHost(QString("something.invalid"), 0, 0); + QProcess::execute("yjhbrty"); + QProcess::startDetached("yjhbrty"); +#endif +} + +//----------------------------------------------------------------------------- +void tst_QProcess::atEnd2() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess process; + +#ifdef Q_OS_MAC + process.start("testProcessEcho/testProcessEcho.app"); +#else + process.start("testProcessEcho/testProcessEcho"); +#endif + process.write("Foo\nBar\nBaz\nBodukon\nHadukan\nTorwukan\nend\n"); + process.putChar('\0'); + QVERIFY(process.waitForFinished()); + QList<QByteArray> lines; + while (!process.atEnd()) { + lines << process.readLine(); + } + QCOMPARE(lines.size(), 7); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::waitForReadyReadForNonexistantProcess() +{ + // This comes from task 108968 + // Start a program that doesn't exist, process events and then try to waitForReadyRead + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); + + QProcess process; + QSignalSpy errorSpy(&process, SIGNAL(error(QProcess::ProcessError))); + QSignalSpy finishedSpy1(&process, SIGNAL(finished(int))); + QSignalSpy finishedSpy2(&process, SIGNAL(finished(int, QProcess::ExitStatus))); + QVERIFY(!process.waitForReadyRead()); // used to crash + process.start("doesntexist"); + QVERIFY(!process.waitForReadyRead()); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorSpy.at(0).at(0).toInt(), 0); + QCOMPARE(finishedSpy1.count(), 0); + QCOMPARE(finishedSpy2.count(), 0); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::setStandardInputFile() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + static const char data[] = "A bunch\1of\2data\3\4\5\6\7..."; + QProcess process; + QFile file("data"); + + QVERIFY(file.open(QIODevice::WriteOnly)); + file.write(data, sizeof data); + file.close(); + + process.setStandardInputFile("data"); +#ifdef Q_OS_MAC + process.start("testProcessEcho/testProcessEcho.app"); +#else + process.start("testProcessEcho/testProcessEcho"); +#endif + + QPROCESS_VERIFY(process, waitForFinished()); + QByteArray all = process.readAll(); + QCOMPARE(all.size(), int(sizeof data) - 1); // testProcessEcho drops the ending \0 + QVERIFY(all == data); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::setStandardOutputFile_data() +{ + QTest::addColumn<int>("channelToTest"); + QTest::addColumn<int>("_channelMode"); + QTest::addColumn<bool>("append"); + + QTest::newRow("stdout-truncate") << int(QProcess::StandardOutput) + << int(QProcess::SeparateChannels) + << false; + QTest::newRow("stdout-append") << int(QProcess::StandardOutput) + << int(QProcess::SeparateChannels) + << true; + + QTest::newRow("stderr-truncate") << int(QProcess::StandardError) + << int(QProcess::SeparateChannels) + << false; + QTest::newRow("stderr-append") << int(QProcess::StandardError) + << int(QProcess::SeparateChannels) + << true; + + QTest::newRow("merged-truncate") << int(QProcess::StandardOutput) + << int(QProcess::MergedChannels) + << false; + QTest::newRow("merged-append") << int(QProcess::StandardOutput) + << int(QProcess::MergedChannels) + << true; +} + +void tst_QProcess::setStandardOutputFile() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + static const char data[] = "Original data. "; + static const char testdata[] = "Test data."; + + QFETCH(int, channelToTest); + QFETCH(int, _channelMode); + QFETCH(bool, append); + + QProcess::ProcessChannelMode channelMode = QProcess::ProcessChannelMode(_channelMode); + QIODevice::OpenMode mode = append ? QIODevice::Append : QIODevice::Truncate; + + // create the destination file with data + QFile file("data"); + QVERIFY(file.open(QIODevice::WriteOnly)); + file.write(data, sizeof data - 1); + file.close(); + + // run the process + QProcess process; + process.setReadChannelMode(channelMode); + if (channelToTest == QProcess::StandardOutput) + process.setStandardOutputFile("data", mode); + else + process.setStandardErrorFile("data", mode); + +#ifdef Q_OS_MAC + process.start("testProcessEcho2/testProcessEcho2.app"); +#else + process.start("testProcessEcho2/testProcessEcho2"); +#endif + process.write(testdata, sizeof testdata); + QPROCESS_VERIFY(process,waitForFinished()); + + // open the file again and verify the data + QVERIFY(file.open(QIODevice::ReadOnly)); + QByteArray all = file.readAll(); + file.close(); + + int expectedsize = sizeof testdata - 1; + if (mode == QIODevice::Append) { + QVERIFY(all.startsWith(data)); + expectedsize += sizeof data - 1; + } + if (channelMode == QProcess::MergedChannels) { + expectedsize += sizeof testdata - 1; + } else { + QVERIFY(all.endsWith(testdata)); + } + + QCOMPARE(all.size(), expectedsize); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::setStandardOutputProcess_data() +{ + QTest::addColumn<bool>("merged"); + QTest::newRow("separate") << false; + QTest::newRow("merged") << true; +} + +void tst_QProcess::setStandardOutputProcess() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QProcess source; + QProcess sink; + + QFETCH(bool, merged); + source.setReadChannelMode(merged ? QProcess::MergedChannels : QProcess::SeparateChannels); + source.setStandardOutputProcess(&sink); + +#ifdef Q_OS_MAC + source.start("testProcessEcho2/testProcessEcho2.app"); + sink.start("testProcessEcho2/testProcessEcho2.app"); +#else + source.start("testProcessEcho2/testProcessEcho2"); + sink.start("testProcessEcho2/testProcessEcho2"); +#endif + + QByteArray data("Hello, World"); + source.write(data); + source.closeWriteChannel(); + QPROCESS_VERIFY(source, waitForFinished()); + QPROCESS_VERIFY(sink, waitForFinished()); + QByteArray all = sink.readAll(); + + if (!merged) + QCOMPARE(all, data); + else + QCOMPARE(all, QByteArray("HHeelllloo,, WWoorrlldd")); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::fileWriterProcess() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + + QString stdinStr; + for (int i = 0; i < 5000; ++i) + stdinStr += QString::fromLatin1("%1 -- testing testing 1 2 3\n").arg(i); + + QTime stopWatch; + stopWatch.start(); + do { + QFile::remove("fileWriterProcess.txt"); + QProcess process; + process.start("fileWriterProcess/fileWriterProcess", + QIODevice::ReadWrite | QIODevice::Text); + process.write(stdinStr.toLatin1()); + process.closeWriteChannel(); + while (process.bytesToWrite()) { + QVERIFY(stopWatch.elapsed() < 3500); + QVERIFY(process.waitForBytesWritten(2000)); + } + QVERIFY(process.waitForFinished()); + QCOMPARE(QFile("fileWriterProcess.txt").size(), qint64(stdinStr.size())); + } while (stopWatch.elapsed() < 3000); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::detachedWorkingDirectoryAndPid() +{ +#if defined(Q_OS_SYMBIAN) && defined(Q_CC_NOKIAX86) + // WINSCW builds in Symbian do not allow multiple processes to load Qt libraries, + // so this test must be skipped. + QSKIP("Multiple processes loading Qt are not allowed in Qt/Symbian emulator.", SkipAll); +#endif + qint64 pid; + +#ifdef Q_OS_WINCE + QTest::qSleep(1000); +#endif + +#if defined(Q_OS_SYMBIAN) + // Symbian has no working directory support, so use logs dir as a shared directory + QFile infoFile(QLatin1String("c:\\logs\\detachedinfo.txt")); +#else + QFile infoFile(QDir::currentPath() + QLatin1String("/detachedinfo.txt")); +#endif + infoFile.remove(); + + QString workingDir = QDir::currentPath() + "/testDetached"; + +#ifndef Q_OS_SYMBIAN + QVERIFY(QFile::exists(workingDir)); +#endif + + QStringList args; + args << infoFile.fileName(); + QVERIFY(QProcess::startDetached(QDir::currentPath() + QLatin1String("/testDetached/testDetached"), args, workingDir, &pid)); + + QFileInfo fi(infoFile); + fi.setCaching(false); + //The guard counter ensures the test does not hang if the sub process fails. + //Instead, the test will fail when trying to open & verify the sub process output file. + for (int guard = 0; guard < 100 && fi.size() == 0; guard++) { + QTest::qSleep(100); + } + + QVERIFY(infoFile.open(QIODevice::ReadOnly | QIODevice::Text)); + QString actualWorkingDir = QString::fromUtf8(infoFile.readLine()); + actualWorkingDir.chop(1); // strip off newline + QByteArray processIdString = infoFile.readLine(); + processIdString.chop(1); + infoFile.close(); + infoFile.remove(); + + bool ok = false; + qint64 actualPid = processIdString.toLongLong(&ok); + QVERIFY(ok); + +#if defined(Q_OS_SYMBIAN) + QEXPECT_FAIL("", "Working directory is not supported on Qt/symbian", Continue); +#endif + QCOMPARE(actualWorkingDir, workingDir); + QCOMPARE(actualPid, pid); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::switchReadChannels() +{ +#ifdef Q_OS_WINCE + QSKIP("Reading and writing to a process is not supported on Qt/CE", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Reading and writing to a process is not supported on Qt/Symbian", SkipAll); +#endif + const char data[] = "ABCD"; + + QProcess process; + +#ifdef Q_OS_MAC + process.start("testProcessEcho2/testProcessEcho2.app"); +#else + process.start("testProcessEcho2/testProcessEcho2"); +#endif + process.write(data); + process.closeWriteChannel(); + QVERIFY(process.waitForFinished(5000)); + + for (int i = 0; i < 4; ++i) { + process.setReadChannel(QProcess::StandardOutput); + QCOMPARE(process.read(1), QByteArray(&data[i], 1)); + process.setReadChannel(QProcess::StandardError); + QCOMPARE(process.read(1), QByteArray(&data[i], 1)); + } + + process.ungetChar('D'); + process.setReadChannel(QProcess::StandardOutput); + process.ungetChar('D'); + process.setReadChannel(QProcess::StandardError); + QCOMPARE(process.read(1), QByteArray("D")); + process.setReadChannel(QProcess::StandardOutput); + QCOMPARE(process.read(1), QByteArray("D")); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::setWorkingDirectory() +{ +#ifdef Q_OS_WINCE + QSKIP("Windows CE does not support working directory logic", SkipAll); +#endif +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian does not support working directory logic", SkipAll); +#endif + process = new QProcess; + process->setWorkingDirectory("test"); +#ifdef Q_OS_MAC + process->start("testSetWorkingDirectory/testSetWorkingDirectory.app"); +#else + process->start("testSetWorkingDirectory/testSetWorkingDirectory"); +#endif +#ifndef Q_OS_WIN + QSKIP("setWorkingDirectory will chdir before starting the process on unices", SkipAll); +#endif + QVERIFY(process->waitForFinished()); + + QByteArray workingDir = process->readAllStandardOutput(); + QCOMPARE(QDir("test").canonicalPath(), QDir(workingDir.constData()).canonicalPath()); + + delete process; + process = 0; +} + +//----------------------------------------------------------------------------- +void tst_QProcess::startFinishStartFinish() +{ + QProcess process; + + for (int i = 0; i < 3; ++i) { + QCOMPARE(process.state(), QProcess::NotRunning); + +#ifdef Q_OS_MAC + process.start("testProcessOutput/testProcessOutput.app"); +#else + process.start("testProcessOutput/testProcessOutput"); +#endif +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QVERIFY(process.waitForReadyRead(10000)); + QCOMPARE(QString::fromLatin1(process.readLine().trimmed()), + QString("0 -this is a number")); +#endif + if (process.state() != QProcess::NotRunning) + QVERIFY(process.waitForFinished(10000)); +#if defined(Q_OS_SYMBIAN) + // Symbian test outputs to a file, so check that + FILE* file = fopen("c:\\logs\\qprocess_output_test.txt","r"); + QVERIFY(file); + char buf[30]; + fgets(buf, 30, file); + QCOMPARE(QString::fromLatin1(buf), + QString("0 -this is a number\n")); + fclose(file); +#endif + } +} + +//----------------------------------------------------------------------------- +void tst_QProcess::invalidProgramString_data() +{ + QTest::addColumn<QString>("programString"); + QTest::newRow("null string") << QString(); + QTest::newRow("empty string") << QString(""); + QTest::newRow("only blank string") << QString(" "); +} + +void tst_QProcess::invalidProgramString() +{ + QFETCH(QString, programString); + QProcess process; + + qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError"); + QSignalSpy spy(&process, SIGNAL(error(QProcess::ProcessError))); + + process.start(programString); + QCOMPARE(process.error(), QProcess::FailedToStart); + QCOMPARE(spy.count(), 1); + + QVERIFY(!QProcess::startDetached(programString)); +} + +//----------------------------------------------------------------------------- +void tst_QProcess::onlyOneStartedSignal() +{ + QProcess process; + + QSignalSpy spyStarted(&process, SIGNAL(started())); + QSignalSpy spyFinished(&process, SIGNAL(finished(int, QProcess::ExitStatus))); + + process.start("testProcessNormal/testProcessNormal"); + QVERIFY(process.waitForStarted(5000)); + QVERIFY(process.waitForFinished(5000)); + QCOMPARE(spyStarted.count(), 1); + QCOMPARE(spyFinished.count(), 1); + + spyStarted.clear(); + spyFinished.clear(); + + process.start("testProcessNormal/testProcessNormal"); + QVERIFY(process.waitForFinished(5000)); + QCOMPARE(spyStarted.count(), 1); + QCOMPARE(spyFinished.count(), 1); +} + +QTEST_MAIN(tst_QProcess) +#include "tst_qprocess.moc" +#endif + diff --git a/tests/auto/corelib/io/qprocessenvironment/qprocessenvironment.pro b/tests/auto/corelib/io/qprocessenvironment/qprocessenvironment.pro new file mode 100644 index 0000000000..60dba50813 --- /dev/null +++ b/tests/auto/corelib/io/qprocessenvironment/qprocessenvironment.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +QT = core + +SOURCES += tst_qprocessenvironment.cpp +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp new file mode 100644 index 0000000000..d88ffdedb7 --- /dev/null +++ b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest> +#include <QObject> +#include <QProcessEnvironment> + +class tst_QProcessEnvironment: public QObject +{ + Q_OBJECT +private slots: + void operator_eq(); + void clearAndIsEmpty(); + void insert(); + void emptyNull(); + void toStringList(); + void keys(); + void insertEnv(); + + void caseSensitivity(); + void systemEnvironment(); + void putenv(); +}; + +void tst_QProcessEnvironment::operator_eq() +{ + QProcessEnvironment e1; + QVERIFY(e1 == e1); + e1.clear(); + QVERIFY(e1 == e1); + + e1 = QProcessEnvironment(); + QProcessEnvironment e2; + QVERIFY(e1 == e2); + + e1.clear(); + QVERIFY(e1 != e2); + + e2.clear(); + + QVERIFY(e1 == e2); +} + +void tst_QProcessEnvironment::clearAndIsEmpty() +{ + QProcessEnvironment e; + e.insert("FOO", "bar"); + QVERIFY(!e.isEmpty()); + e.clear(); + QVERIFY(e.isEmpty()); +} + +void tst_QProcessEnvironment::insert() +{ + QProcessEnvironment e; + e.insert("FOO", "bar"); + QVERIFY(!e.isEmpty()); + QVERIFY(e.contains("FOO")); + QCOMPARE(e.value("FOO"), QString("bar")); + + e.remove("FOO"); + QVERIFY(!e.contains("FOO")); + QVERIFY(e.value("FOO").isNull()); + + e.clear(); + QVERIFY(!e.contains("FOO")); +} + +void tst_QProcessEnvironment::emptyNull() +{ + QProcessEnvironment e; + + e.insert("FOO", ""); + QVERIFY(e.contains("FOO")); + QVERIFY(e.value("FOO").isEmpty()); + QVERIFY(!e.value("FOO").isNull()); + + e.insert("FOO", QString()); + QVERIFY(e.contains("FOO")); + QVERIFY(e.value("FOO").isEmpty()); + // don't test if it's NULL, since we shall not make a guarantee + + e.remove("FOO"); + QVERIFY(!e.contains("FOO")); +} + +void tst_QProcessEnvironment::toStringList() +{ + QProcessEnvironment e; + QVERIFY(e.isEmpty()); + QVERIFY(e.toStringList().isEmpty()); + + e.insert("FOO", "bar"); + QStringList result = e.toStringList(); + QVERIFY(!result.isEmpty()); + QCOMPARE(result.length(), 1); + QCOMPARE(result.at(0), QString("FOO=bar")); + + e.clear(); + e.insert("BAZ", ""); + result = e.toStringList(); + QCOMPARE(result.at(0), QString("BAZ=")); + + e.insert("FOO", "bar"); + e.insert("A", "bc"); + e.insert("HELLO", "World"); + result = e.toStringList(); + QCOMPARE(result.length(), 4); + + // order is not specified, so use contains() + QVERIFY(result.contains("FOO=bar")); + QVERIFY(result.contains("BAZ=")); + QVERIFY(result.contains("A=bc")); + QVERIFY(result.contains("HELLO=World")); +} + +void tst_QProcessEnvironment::keys() +{ + QProcessEnvironment e; + QVERIFY(e.isEmpty()); + QVERIFY(e.keys().isEmpty()); + + e.insert("FOO", "bar"); + QStringList result = e.keys(); + QCOMPARE(result.length(), 1); + QCOMPARE(result.at(0), QString("FOO")); + + e.clear(); + e.insert("BAZ", ""); + result = e.keys(); + QCOMPARE(result.at(0), QString("BAZ")); + + e.insert("FOO", "bar"); + e.insert("A", "bc"); + e.insert("HELLO", "World"); + result = e.keys(); + QCOMPARE(result.length(), 4); + + // order is not specified, so use contains() + QVERIFY(result.contains("FOO")); + QVERIFY(result.contains("BAZ")); + QVERIFY(result.contains("A")); + QVERIFY(result.contains("HELLO")); +} + +void tst_QProcessEnvironment::insertEnv() +{ + QProcessEnvironment e; + e.insert("FOO", "bar"); + e.insert("A", "bc"); + e.insert("Hello", "World"); + + QProcessEnvironment e2; + e2.insert("FOO2", "bar2"); + e2.insert("A2", "bc2"); + e2.insert("Hello", "Another World"); + + e.insert(e2); + QStringList keys = e.keys(); + QCOMPARE(keys.length(), 5); + + QCOMPARE(e.value("FOO"), QString("bar")); + QCOMPARE(e.value("A"), QString("bc")); + QCOMPARE(e.value("Hello"), QString("Another World")); + QCOMPARE(e.value("FOO2"), QString("bar2")); + QCOMPARE(e.value("A2"), QString("bc2")); +} + +void tst_QProcessEnvironment::caseSensitivity() +{ + QProcessEnvironment e; + e.insert("foo", "bar"); + +#ifdef Q_OS_WIN + // Windows is case-insensitive, but case-preserving + QVERIFY(e.contains("foo")); + QVERIFY(e.contains("FOO")); + QVERIFY(e.contains("FoO")); + + QCOMPARE(e.value("foo"), QString("bar")); + QCOMPARE(e.value("FOO"), QString("bar")); + QCOMPARE(e.value("FoO"), QString("bar")); + + // Per Windows, this overwrites the value, but keeps the name's original capitalization + e.insert("Foo", "Bar"); + + QStringList list = e.toStringList(); + QCOMPARE(list.length(), 1); + QCOMPARE(list.at(0), QString("foo=Bar")); +#else + // otherwise, it's case sensitive + QVERIFY(e.contains("foo")); + QVERIFY(!e.contains("FOO")); + + e.insert("FOO", "baz"); + QVERIFY(e.contains("FOO")); + QCOMPARE(e.value("FOO"), QString("baz")); + QCOMPARE(e.value("foo"), QString("bar")); + + QStringList list = e.toStringList(); + QCOMPARE(list.length(), 2); + QVERIFY(list.contains("foo=bar")); + QVERIFY(list.contains("FOO=baz")); +#endif +} + +void tst_QProcessEnvironment::systemEnvironment() +{ + static const char envname[] = "THIS_ENVIRONMENT_VARIABLE_HOPEFULLY_DOESNT_EXIST"; + QByteArray path = qgetenv("PATH"); + QByteArray nonexistant = qgetenv(envname); + QProcessEnvironment system = QProcessEnvironment::systemEnvironment(); + + QVERIFY(nonexistant.isNull()); + +#ifdef Q_WS_WINCE + // Windows CE has no environment + QVERIFY(path.isEmpty()); + QVERIFY(!system.contains("PATH")); + QVERIFY(system.isEmpty()); +#else + // all other system have environments + if (path.isEmpty()) + QFAIL("Could not find the PATH environment variable -- please correct the test environment"); + + QVERIFY(system.contains("PATH")); + QCOMPARE(system.value("PATH"), QString::fromLocal8Bit(path)); + + QVERIFY(!system.contains(envname)); + +# ifdef Q_OS_WIN + // check case-insensitive too + QVERIFY(system.contains("path")); + QCOMPARE(system.value("path"), QString::fromLocal8Bit(path)); + + QVERIFY(!system.contains(QString(envname).toLower())); +# endif +#endif +} + +void tst_QProcessEnvironment::putenv() +{ +#ifdef Q_WS_WINCE + QSKIP("Windows CE has no environment", SkipAll); +#else + static const char envname[] = "WE_RE_SETTING_THIS_ENVIRONMENT_VARIABLE"; + static bool testRan = false; + + if (testRan) + QFAIL("You cannot run this test more than once, since we modify the environment"); + testRan = true; + + QByteArray valBefore = qgetenv(envname); + if (!valBefore.isNull()) + QFAIL("The environment variable we set in the environment is already set! -- please correct the test environment"); + QProcessEnvironment eBefore = QProcessEnvironment::systemEnvironment(); + + qputenv(envname, "Hello, World"); + QByteArray valAfter = qgetenv(envname); + if (valAfter != "Hello, World") + QSKIP("Could not test: qputenv did not do its job", SkipAll); + + QProcessEnvironment eAfter = QProcessEnvironment::systemEnvironment(); + + QVERIFY(!eBefore.contains(envname)); + QVERIFY(eAfter.contains(envname)); + QCOMPARE(eAfter.value(envname), QString("Hello, World")); + +# ifdef Q_OS_WIN + // check case-insensitive too + QString lower = envname; + lower = lower.toLower(); + QVERIFY(!eBefore.contains(lower)); + QVERIFY(eAfter.contains(lower)); + QCOMPARE(eAfter.value(lower), QString("Hello, World")); +# endif +#endif +} + +QTEST_MAIN(tst_QProcessEnvironment) + +#include "tst_qprocessenvironment.moc" diff --git a/tests/auto/corelib/io/qresourceengine/.gitattributes b/tests/auto/corelib/io/qresourceengine/.gitattributes new file mode 100644 index 0000000000..add3716d81 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/.gitattributes @@ -0,0 +1 @@ +testqrc/test.qrc -crlf diff --git a/tests/auto/corelib/io/qresourceengine/.gitignore b/tests/auto/corelib/io/qresourceengine/.gitignore new file mode 100644 index 0000000000..eb48d60239 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/.gitignore @@ -0,0 +1 @@ +tst_qresourceengine diff --git a/tests/auto/corelib/io/qresourceengine/parentdir.txt b/tests/auto/corelib/io/qresourceengine/parentdir.txt new file mode 100644 index 0000000000..a94edee379 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/parentdir.txt @@ -0,0 +1 @@ +abcdefgihklmnopqrstuvwxyz diff --git a/tests/auto/corelib/io/qresourceengine/qresourceengine.pro b/tests/auto/corelib/io/qresourceengine/qresourceengine.pro new file mode 100644 index 0000000000..abbf39bd83 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/qresourceengine.pro @@ -0,0 +1,47 @@ +###################################################################### +# Automatically generated by qmake (2.00a) ma 2. mai 16:14:33 2005 +###################################################################### + +load(qttest_p4) +load(resources) + +# Input +SOURCES += tst_qresourceengine.cpp +RESOURCES += testqrc/test.qrc + +symbian-sbsv2 { + runtime_resource.target = $$PWD/runtime_resource.rcc +} else { + runtime_resource.target = runtime_resource.rcc +} +runtime_resource.depends = $$PWD/testqrc/test.qrc +runtime_resource.commands = $$QMAKE_RCC -root /runtime_resource/ -binary $${runtime_resource.depends} -o $${runtime_resource.target} +QMAKE_EXTRA_TARGETS = runtime_resource +PRE_TARGETDEPS += $${runtime_resource.target} + +QT = core +wince*|symbian:{ + deploy.files += runtime_resource.rcc parentdir.txt + test.files = testqrc/* + test.path = testqrc + alias.files = testqrc/aliasdir/* + alias.path = testqrc/aliasdir + other.files = testqrc/otherdir/* + other.path = testqrc/otherdir + search1.files = testqrc/searchpath1/* + search1.path = testqrc/searchpath1 + search2.files = testqrc/searchpath2/* + search2.path = testqrc/searchpath2 + sub.files = testqrc/subdir/* + sub.path = testqrc/subdir + testsub.files = testqrc/test/* + testsub.path = testqrc/test + testsub2.files = testqrc/test/test/* + testsub2.path = testqrc/test/test + DEPLOYMENT += deploy test alias other search1 search2 sub testsub testsub2 + !symbian:DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} +CONFIG += parallel_test +CONFIG += insignificant_test # QTBUG-21159 diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/aliasdir/aliasdir.txt b/tests/auto/corelib/io/qresourceengine/testqrc/aliasdir/aliasdir.txt new file mode 100644 index 0000000000..21a3dfa0b8 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/aliasdir/aliasdir.txt @@ -0,0 +1 @@ +"This is a korean text file" diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/aliasdir/compressme.txt b/tests/auto/corelib/io/qresourceengine/testqrc/aliasdir/compressme.txt new file mode 100644 index 0000000000..bd596cdacd --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/aliasdir/compressme.txt @@ -0,0 +1,322 @@ +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/blahblah.txt b/tests/auto/corelib/io/qresourceengine/testqrc/blahblah.txt new file mode 100644 index 0000000000..436c4d11c3 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/blahblah.txt @@ -0,0 +1 @@ +qwerty diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/currentdir.txt b/tests/auto/corelib/io/qresourceengine/testqrc/currentdir.txt new file mode 100644 index 0000000000..38e389979a --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/currentdir.txt @@ -0,0 +1 @@ +"This is the current dir" diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/currentdir2.txt b/tests/auto/corelib/io/qresourceengine/testqrc/currentdir2.txt new file mode 100644 index 0000000000..6ac16a3306 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/currentdir2.txt @@ -0,0 +1 @@ +"This is also the current dir" diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/otherdir/otherdir.txt b/tests/auto/corelib/io/qresourceengine/testqrc/otherdir/otherdir.txt new file mode 100644 index 0000000000..b0e4a124ee --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/otherdir/otherdir.txt @@ -0,0 +1 @@ +"This is the other dir" diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/search_file.txt b/tests/auto/corelib/io/qresourceengine/testqrc/search_file.txt new file mode 100644 index 0000000000..d8649da39d --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/search_file.txt @@ -0,0 +1 @@ +root diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/searchpath1/search_file.txt b/tests/auto/corelib/io/qresourceengine/testqrc/searchpath1/search_file.txt new file mode 100644 index 0000000000..3f31b59496 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/searchpath1/search_file.txt @@ -0,0 +1 @@ +path1 diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/searchpath2/search_file.txt b/tests/auto/corelib/io/qresourceengine/testqrc/searchpath2/search_file.txt new file mode 100644 index 0000000000..8e3be1fa2e --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/searchpath2/search_file.txt @@ -0,0 +1 @@ +path2 diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/subdir/subdir.txt b/tests/auto/corelib/io/qresourceengine/testqrc/subdir/subdir.txt new file mode 100644 index 0000000000..b6115207a2 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/subdir/subdir.txt @@ -0,0 +1 @@ +"This is in the sub directory" diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/test.qrc b/tests/auto/corelib/io/qresourceengine/testqrc/test.qrc new file mode 100644 index 0000000000..f5e8c849a6 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/test.qrc @@ -0,0 +1,30 @@ +<!DOCTYPE RCC><RCC version="1.0">
+ <qresource prefix="/test/abc/123/+++">
+ <file>currentdir.txt</file>
+ <file>./currentdir2.txt</file>
+ <file>../parentdir.txt</file>
+ <file>subdir/subdir.txt</file>
+ </qresource>
+ <qresource prefix="/">
+ <file>searchpath1/search_file.txt</file>
+ <file>searchpath2/search_file.txt</file>
+ <file>search_file.txt</file>
+ </qresource>
+ <qresource><file>test/testdir.txt</file>
+ <file>otherdir/otherdir.txt</file>
+ <file alias="aliasdir/aliasdir.txt">test/testdir2.txt</file>
+ <file>test/test</file>
+ </qresource>
+ <qresource lang="ko">
+ <file>aliasdir/aliasdir.txt</file>
+ </qresource>
+ <qresource lang="de_CH">
+ <file alias="aliasdir/aliasdir.txt" compress="9" threshold="30">aliasdir/compressme.txt</file>
+ </qresource>
+ <qresource lang="de">
+ <file alias="aliasdir/aliasdir.txt">test/german.txt</file>
+ </qresource>
+ <qresource prefix="withoutslashes">
+ <file>blahblah.txt</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/test/german.txt b/tests/auto/corelib/io/qresourceengine/testqrc/test/german.txt new file mode 100644 index 0000000000..12b1cb7320 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/test/german.txt @@ -0,0 +1 @@ +Deutsch diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/test/test/test1.txt b/tests/auto/corelib/io/qresourceengine/testqrc/test/test/test1.txt new file mode 100644 index 0000000000..adc01d1354 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/test/test/test1.txt @@ -0,0 +1 @@ +abc diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/test/test/test2.txt b/tests/auto/corelib/io/qresourceengine/testqrc/test/test/test2.txt new file mode 100644 index 0000000000..3f48e3cdc3 --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/test/test/test2.txt @@ -0,0 +1 @@ +def diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/test/testdir.txt b/tests/auto/corelib/io/qresourceengine/testqrc/test/testdir.txt new file mode 100644 index 0000000000..40ee68dccb --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/test/testdir.txt @@ -0,0 +1 @@ +"This is in the test directory" diff --git a/tests/auto/corelib/io/qresourceengine/testqrc/test/testdir2.txt b/tests/auto/corelib/io/qresourceengine/testqrc/test/testdir2.txt new file mode 100644 index 0000000000..051430298a --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/testqrc/test/testdir2.txt @@ -0,0 +1 @@ +"This is another file in this directory" diff --git a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp new file mode 100644 index 0000000000..7914fc8bfc --- /dev/null +++ b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp @@ -0,0 +1,488 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore> + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "." +#endif + +class tst_QResourceEngine: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void checkUnregisterResource_data(); + void checkUnregisterResource(); + void checkStructure_data(); + void checkStructure(); + void searchPath_data(); + void searchPath(); + void doubleSlashInRoot(); + void setLocale(); + +private: + QString builddir; +}; + +Q_DECLARE_METATYPE(QLocale) +Q_DECLARE_METATYPE(qlonglong) + +void tst_QResourceEngine::initTestCase() +{ + QVERIFY(QResource::registerResource("runtime_resource.rcc")); + QVERIFY(QResource::registerResource("runtime_resource.rcc", "/secondary_root/")); + QString srcdir(QLatin1String(SRCDIR)); + if (!srcdir.isEmpty()) { + builddir = QDir::current().absolutePath(); + if (!builddir.endsWith(QDir::separator())) + builddir.append(QDir::separator()); + QDir::setCurrent(srcdir); + } +} + +void tst_QResourceEngine::cleanupTestCase() +{ + if (!builddir.isEmpty()) { + QDir::setCurrent(builddir); + } + + // make sure we don't leak memory + QVERIFY(QResource::unregisterResource("runtime_resource.rcc")); + QVERIFY(QResource::unregisterResource("runtime_resource.rcc", "/secondary_root/")); +} + +void tst_QResourceEngine::checkStructure_data() +{ + QTest::addColumn<QString>("pathName"); + QTest::addColumn<QString>("contents"); + QTest::addColumn<QStringList>("containedFiles"); + QTest::addColumn<QStringList>("containedDirs"); + QTest::addColumn<QLocale>("locale"); + QTest::addColumn<qlonglong>("contentsSize"); + + QFileInfo info; + + QTest::newRow("root dir") << QString(":/") + << QString() + << (QStringList() << "search_file.txt") + << (QStringList() << QLatin1String("aliasdir") << QLatin1String("otherdir") + << QLatin1String("runtime_resource") + << QLatin1String("searchpath1") << QLatin1String("searchpath2") + << QLatin1String("secondary_root") + << QLatin1String("test") + << QLatin1String("withoutslashes")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow("secondary root") << QString(":/secondary_root/") + << QString() + << QStringList() + << (QStringList() << QLatin1String("runtime_resource")) + << QLocale::c() + << qlonglong(0); + + QStringList roots; + roots << QString(":/") << QString(":/runtime_resource/") << QString(":/secondary_root/runtime_resource/"); + for(int i = 0; i < roots.size(); ++i) { + const QString root = roots.at(i); + + QTest::newRow(QString(root + "prefix dir").toLatin1().constData()) << QString(root + "test/abc/123/+++") + << QString() + << (QStringList() << QLatin1String("currentdir.txt") << QLatin1String("currentdir2.txt") << QLatin1String("parentdir.txt")) + << (QStringList() << QLatin1String("subdir")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "parent to prefix").toLatin1().constData()) << QString(root + "test/abc/123") + << QString() + << QStringList() + << (QStringList() << QLatin1String("+++")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "two parents prefix").toLatin1().constData()) << QString(root + "test/abc") + << QString() + << QStringList() + << QStringList(QLatin1String("123")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "test dir ").toLatin1().constData()) << QString(root + "test") + << QString() + << (QStringList() << QLatin1String("testdir.txt")) + << (QStringList() << QLatin1String("abc") << QLatin1String("test")) + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "prefix no slashes").toLatin1().constData()) << QString(root + "withoutslashes") + << QString() + << QStringList("blahblah.txt") + << QStringList() + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "other dir").toLatin1().constData()) << QString(root + "otherdir") + << QString() + << QStringList(QLatin1String("otherdir.txt")) + << QStringList() + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "alias dir").toLatin1().constData()) << QString(root + "aliasdir") + << QString() + << QStringList(QLatin1String("aliasdir.txt")) + << QStringList() + << QLocale::c() + << qlonglong(0); + + QTest::newRow(QString(root + "second test dir").toLatin1().constData()) << QString(root + "test/test") + << QString() + << (QStringList() << QLatin1String("test1.txt") << QLatin1String("test2.txt")) + << QStringList() + << QLocale::c() + << qlonglong(0); + + info = QFileInfo("testqrc/test/test/test1.txt"); + QTest::newRow(QString(root + "test1 text").toLatin1().constData()) << QString(root + "test/test/test1.txt") + << QString("abc") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/blahblah.txt"); + QTest::newRow(QString(root + "text no slashes").toLatin1().constData()) << QString(root + "withoutslashes/blahblah.txt") + << QString("qwerty") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + + info = QFileInfo("testqrc/test/test/test2.txt"); + QTest::newRow(QString(root + "test1 text").toLatin1().constData()) << QString(root + "test/test/test2.txt") + << QString("def") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/currentdir.txt"); + QTest::newRow(QString(root + "currentdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/currentdir.txt") + << QString("\"This is the current dir\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/currentdir2.txt"); + QTest::newRow(QString(root + "currentdir text2").toLatin1().constData()) << QString(root + "test/abc/123/+++/currentdir2.txt") + << QString("\"This is also the current dir\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("parentdir.txt"); + QTest::newRow(QString(root + "parentdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/parentdir.txt") + << QString("abcdefgihklmnopqrstuvwxyz ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/subdir/subdir.txt"); + QTest::newRow(QString(root + "subdir text").toLatin1().constData()) << QString(root + "test/abc/123/+++/subdir/subdir.txt") + << QString("\"This is in the sub directory\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/testdir.txt"); + QTest::newRow(QString(root + "testdir text").toLatin1().constData()) << QString(root + "test/testdir.txt") + << QString("\"This is in the test directory\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/otherdir/otherdir.txt"); + QTest::newRow(QString(root + "otherdir text").toLatin1().constData()) << QString(root + "otherdir/otherdir.txt") + << QString("\"This is the other dir\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/testdir2.txt"); + QTest::newRow(QString(root + "alias text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("\"This is another file in this directory\" ") + << QStringList() + << QStringList() + << QLocale::c() + << qlonglong(info.size()); + + info = QFileInfo("testqrc/aliasdir/aliasdir.txt"); + QTest::newRow(QString(root + "korean text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("\"This is a korean text file\" ") + << QStringList() + << QStringList() + << QLocale("ko") + << qlonglong(info.size()); + + info = QFileInfo("testqrc/aliasdir/aliasdir.txt"); + QTest::newRow(QString(root + "korean text 2").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("\"This is a korean text file\" ") + << QStringList() + << QStringList() + << QLocale("ko_KR") + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/german.txt"); + QTest::newRow(QString(root + "german text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("Deutsch") + << QStringList() + << QStringList() + << QLocale("de") + << qlonglong(info.size()); + + info = QFileInfo("testqrc/test/german.txt"); + QTest::newRow(QString(root + "german text 2").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString("Deutsch") + << QStringList() + << QStringList() + << QLocale("de_DE") + << qlonglong(info.size()); + + QFile file("testqrc/aliasdir/compressme.txt"); + file.open(QFile::ReadOnly); + info = QFileInfo("testqrc/aliasdir/compressme.txt"); + QTest::newRow(QString(root + "compressed text").toLatin1().constData()) << QString(root + "aliasdir/aliasdir.txt") + << QString(file.readAll()) + << QStringList() + << QStringList() + << QLocale("de_CH") + << qlonglong(info.size()); + } +} + +void tst_QResourceEngine::checkStructure() +{ + QFETCH(QString, pathName); + QFETCH(QString, contents); + QFETCH(QStringList, containedFiles); + QFETCH(QStringList, containedDirs); + QFETCH(QLocale, locale); + QFETCH(qlonglong, contentsSize); + + bool directory = (containedDirs.size() + containedFiles.size() > 0); + QLocale::setDefault(locale); + + QFileInfo fileInfo(pathName); + + QVERIFY(fileInfo.exists()); + QCOMPARE(fileInfo.isDir(), directory); + QCOMPARE(fileInfo.size(), contentsSize); + //QVERIFY(fileInfo.isReadable()); + QVERIFY(!fileInfo.isWritable()); + QVERIFY(!fileInfo.isExecutable()); + + if (directory) { + QDir dir(pathName); + + // Test the Dir filter + QFileInfoList list = dir.entryInfoList(QDir::Dirs, QDir::Name); +// for(int i = 0; i < list.size(); ++i) +// qDebug() << "one" << i << list.at(i).fileName(); +// for(int i = 0; i < containedDirs.size(); ++i) +// qDebug() << "two" << i << containedDirs.at(i); +// qDebug() << "one" << list.size() << containedDirs.size(); + QCOMPARE(list.size(), containedDirs.size()); +// qDebug() << "two"; + + int i; + for (i=0; i<list.size(); ++i) { + QVERIFY(list.at(i).isDir()); + QCOMPARE(list.at(i).fileName(), containedDirs.at(i)); + } + + list = dir.entryInfoList(QDir::Files, QDir::Name); + QCOMPARE(containedFiles.size(), list.size()); + + for (i=0; i<list.size(); ++i) { + QVERIFY(!list.at(i).isDir()); + QCOMPARE(list.at(i).fileName(), containedFiles.at(i)); + } + + list = dir.entryInfoList(QDir::NoFilter, QDir::SortFlags(QDir::Name | QDir::DirsFirst)); + QCOMPARE(containedFiles.size() + containedDirs.size(), list.size()); + + for (i=0; i<list.size(); ++i) { + QString expectedName; + if (i < containedDirs.size()) + expectedName = containedDirs.at(i); + else + expectedName = containedFiles.at(i - containedDirs.size()); + + QCOMPARE(list.at(i).fileName(), expectedName); + } + } else { + QFile file(pathName); + QVERIFY(file.open(QFile::ReadOnly)); + + QByteArray ba = file.readAll(); + QVERIFY(QString(ba).startsWith(contents)); + } + QLocale::setDefault(QLocale::system()); +} + +void tst_QResourceEngine::searchPath_data() +{ + QTest::addColumn<QString>("searchPath"); + QTest::addColumn<QString>("file"); + QTest::addColumn<QByteArray>("expected"); + + QTest::newRow("no_search_path") << QString() + << ":search_file.txt" + << QByteArray("root\n"); + QTest::newRow("path1") << "/searchpath1" + << ":search_file.txt" + << QByteArray("path1\n"); + QTest::newRow("no_search_path2") << QString() + << ":/search_file.txt" + << QByteArray("root\n"); + QTest::newRow("path2") << "/searchpath2" + << ":search_file.txt" + << QByteArray("path2\n"); +} + +void tst_QResourceEngine::searchPath() +{ + QFETCH(QString, searchPath); + QFETCH(QString, file); + QFETCH(QByteArray, expected); + + if(!searchPath.isEmpty()) + QDir::addResourceSearchPath(searchPath); + QFile qf(file); + QVERIFY(qf.open(QFile::ReadOnly)); + QByteArray actual = qf.readAll(); + + actual.replace('\r', ""); + + QCOMPARE(actual, expected); + qf.close(); +} + +void tst_QResourceEngine::checkUnregisterResource_data() +{ + QTest::addColumn<QString>("rcc_file"); + QTest::addColumn<QString>("root"); + QTest::addColumn<QString>("file_check"); + QTest::addColumn<int>("size"); + + QTest::newRow("currentdir.txt") << builddir + QString("runtime_resource.rcc") << QString("/check_unregister/") + << QString(":/check_unregister/runtime_resource/test/abc/123/+++/currentdir.txt") + << (int)QFileInfo("testqrc/currentdir.txt").size(); +} + +void tst_QResourceEngine::checkUnregisterResource() +{ + QFETCH(QString, rcc_file); + QFETCH(QString, root); + QFETCH(QString, file_check); + QFETCH(int, size); + + + + QVERIFY(!QFile::exists(file_check)); + QVERIFY(QResource::registerResource(rcc_file, root)); + QVERIFY(QFile::exists(file_check)); + QVERIFY(QResource::unregisterResource(rcc_file, root)); + QVERIFY(!QFile::exists(file_check)); + QVERIFY(QResource::registerResource(rcc_file, root)); + QVERIFY(QFile::exists(file_check)); + QFileInfo fileInfo(file_check); + fileInfo.setCaching(false); + QVERIFY(fileInfo.exists()); + QVERIFY(!QResource::unregisterResource(rcc_file, root)); + QVERIFY(!QFile::exists(file_check)); + QCOMPARE((int)fileInfo.size(), size); +} + +void tst_QResourceEngine::doubleSlashInRoot() +{ + QVERIFY(QFile::exists(":/secondary_root/runtime_resource/search_file.txt")); + QVERIFY(QFile::exists("://secondary_root/runtime_resource/search_file.txt")); +} + +void tst_QResourceEngine::setLocale() +{ + QLocale::setDefault(QLocale::c()); + + // default constructed QResource gets the default locale + QResource resource; + resource.setFileName("aliasdir/aliasdir.txt"); + QVERIFY(!resource.isCompressed()); + + // change the default locale and make sure it doesn't affect the resource + QLocale::setDefault(QLocale("de_CH")); + QVERIFY(!resource.isCompressed()); + + // then explicitly set the locale on qresource + resource.setLocale(QLocale("de_CH")); + QVERIFY(resource.isCompressed()); + + // the reset the default locale back + QLocale::setDefault(QLocale::system()); +} + +QTEST_MAIN(tst_QResourceEngine) + +#include "tst_qresourceengine.moc" + diff --git a/tests/auto/corelib/io/qsettings/.gitattributes b/tests/auto/corelib/io/qsettings/.gitattributes new file mode 100644 index 0000000000..a4ad8d7644 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/.gitattributes @@ -0,0 +1,5 @@ +resourcefile.ini -crlf +resourcefile2.ini -crlf +resourcefile3.ini -crlf +resourcefile4.ini -crlf +resourcefile5.ini -crlf diff --git a/tests/auto/corelib/io/qsettings/.gitignore b/tests/auto/corelib/io/qsettings/.gitignore new file mode 100644 index 0000000000..090588b922 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/.gitignore @@ -0,0 +1 @@ +tst_qsettings diff --git a/tests/auto/corelib/io/qsettings/qsettings.pro b/tests/auto/corelib/io/qsettings/qsettings.pro new file mode 100644 index 0000000000..f15e40b267 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/qsettings.pro @@ -0,0 +1,10 @@ +load(qttest_p4) + +QT += core-private + +SOURCES += tst_qsettings.cpp +RESOURCES += qsettings.qrc + +win32-msvc*:LIBS += advapi32.lib + +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qsettings/qsettings.qrc b/tests/auto/corelib/io/qsettings/qsettings.qrc new file mode 100644 index 0000000000..587c22ebe3 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/qsettings.qrc @@ -0,0 +1,9 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>resourcefile.ini</file> + <file>resourcefile2.ini</file> + <file>resourcefile3.ini</file> + <file>resourcefile4.ini</file> + <file>resourcefile5.ini</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qsettings/resourcefile.ini b/tests/auto/corelib/io/qsettings/resourcefile.ini new file mode 100644 index 0000000000..608d1b7885 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/resourcefile.ini @@ -0,0 +1,46 @@ +[Field%201] +Bottom=89 +Flags=MULTILINE|VSCROLL|READONLY +Left=4 +Right=296 +State=No license agreement file found. Please contact support. +Top=14 +Type=Text + +[Field%202] +Bottom=8 +Left=4 +Right=294 +Text=Press Page Down to see the rest of the agreement. +Top=0 +Type=Label + +[Field%203] +Bottom=111 +Left=4 +Right=297 +Text=If you accept the terms of the agreement, select the first option below. You must accept the agreement to install this software. Click Next to continue. +Top=92 +Type=Label + +[Field%204] +Bottom=129 +Flags=GROUP|NOTIFY +Left=4 +Right=299 +Text=I &accept the terms in the License Agreement +Top=120 +Type=RadioButton + +[Field%205] +Bottom=140 +Flags=NOTIFY +Left=4 +Right=300 +State=1 +Text=I &do not accept the terms in the License Agreement +Top=129 +Type=RadioButton + +[Settings] +NumFields=5 diff --git a/tests/auto/corelib/io/qsettings/resourcefile2.ini b/tests/auto/corelib/io/qsettings/resourcefile2.ini new file mode 100644 index 0000000000..cd06b3b4de --- /dev/null +++ b/tests/auto/corelib/io/qsettings/resourcefile2.ini @@ -0,0 +1,46 @@ +[Field%202] +Flags=MULTILINE|VSCROLL|READONLY +Left=4 +Right=296 +State=No license agreement file found. Please contact support. +Bottom=89 +Top=14 +Type=Text + +[Field%201] +Left=4 +Text=Press Page Down to see the rest of the agreement. +Bottom=8 +Top=0 +Right=294 +Type=Label + +[Field%203] +Bottom=111 +Left=4 +Right=297 +Text=If you accept the terms of the agreement, select the first option below. You must accept the agreement to install this software. Click Next to continue. +Top=92 +Type=Label + +[Field%204] +Bottom=129 +Flags=GROUP|NOTIFY +Left=4 +Right=299 +Text=I &accept the terms in the License Agreement +Top=120 +Type=RadioButton + +[Field%205] +Bottom=140 +Flags=NOTIFY +Left=4 +Right=300 +State=1 +Text=I &do not accept the terms in the License Agreement +Top=129 +Type=RadioButton + +[Settings] +NumFields=5 diff --git a/tests/auto/corelib/io/qsettings/resourcefile3.ini b/tests/auto/corelib/io/qsettings/resourcefile3.ini new file mode 100644 index 0000000000..ee54cfbbaf --- /dev/null +++ b/tests/auto/corelib/io/qsettings/resourcefile3.ini @@ -0,0 +1,50 @@ +[Field%202] +Flags=MULTILINE|VSCROLL|READONLY +Left=4 +Right=296 +State=No license agreement file found. Please contact support. +Bottom=89 +Top=14 +Type=Text + +[Field%201] +Left=4 +Text=Press Page Down to see the rest of the agreement. +Bottom=90 +Top=0 +Right=294 +Type=Label +x=1 +y=1 +width=1 +height=1 + +[Field%203] +Bottom=111 +Left=4 +Right=297 +Text=If you accept the terms of the agreement, select the first option below. You must accept the agreement to install this software. Click Next to continue. +Top=92 +Type=Label + +[Field%204] +Bottom=129 +Flags=GROUP|NOTIFY +Left=4 +Right=299 +Text=I &accept the terms in the License Agreement +Top=120 +Type=RadioButton + +[Field%205] +Bottom=140 +Flags=NOTIFY +Left=4 +Right=300 +State=1 +Text=I &do not accept the terms in the License Agreement +Top=129 +Type=RadioButton + +[Settings] +NumFields=5 diff --git a/tests/auto/corelib/io/qsettings/resourcefile4.ini b/tests/auto/corelib/io/qsettings/resourcefile4.ini new file mode 100644 index 0000000000..09c21b1591 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/resourcefile4.ini @@ -0,0 +1,2 @@ +[Fa%E7ade] +QU%C9BEC=Façade/QUÃBEC diff --git a/tests/auto/corelib/io/qsettings/resourcefile5.ini b/tests/auto/corelib/io/qsettings/resourcefile5.ini new file mode 100644 index 0000000000..d2d2103560 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/resourcefile5.ini @@ -0,0 +1,2 @@ +[Fa%E7ade] +QU%C9BEC=Façade/QUÉBEC diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp new file mode 100644 index 0000000000..7436edcd8c --- /dev/null +++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp @@ -0,0 +1,3179 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qdebug.h> +#include <QtTest/QtTest> + +#include <QtCore/QSettings> +#include <private/qsettings_p.h> +//#include <QtGui/QApplication> +#include <QtCore/QCoreApplication> +#include <QtCore/QtGlobal> +#include <QtCore/QMetaType> +#include <QtCore/QtDebug> +#include <QtCore/QString> +#include "../../../../shared/util.h" + +#if !defined(Q_OS_SYMBIAN) +# include <cctype> +#endif +#if defined(Q_OS_WIN) && defined(Q_CC_GNU) +// need for unlink on mingw +#include <io.h> +#endif + +#if defined(Q_OS_WIN) +#include <QtCore/qt_windows.h> +#endif + +#ifndef QSETTINGS_P_H_VERSION +#define QSETTINGS_P_H_VERSION 1 +#endif + +//TESTED_FILES= + +QT_FORWARD_DECLARE_CLASS(QSettings) +QT_FORWARD_DECLARE_CLASS(QSettings) + +class tst_QSettings : public QObject +{ + Q_OBJECT + +public: + tst_QSettings(); + +public slots: + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void ctor_data(); + void ctor(); + void beginGroup(); + void setValue(); + void remove(); + void contains(); + void sync(); + void setFallbacksEnabled(); + void setFallbacksEnabled_data(); + void fromFile_data(); + void fromFile(); + void setIniCodec(); + void testArrays_data(); + void testArrays(); + void testEscapes(); + void testCaseSensitivity_data(); + void testCaseSensitivity(); + void testErrorHandling_data(); + void testErrorHandling(); + void testIniParsing_data(); + void testIniParsing(); + void testChildKeysAndGroups_data(); + void testChildKeysAndGroups(); + void testUpdateRequestEvent(); + void testThreadSafety(); + void testNormalizedKey_data(); + void testNormalizedKey(); + void testEmptyData(); + void testResourceFiles(); + void fileName(); + void isWritable_data(); + void isWritable(); + void childGroups_data(); + void childGroups(); + void childKeys_data(); + void childKeys(); + void allKeys_data(); + void allKeys(); + void registerFormat(); + void setPath(); + void setDefaultFormat(); + void dontCreateNeedlessPaths(); +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) + void dontReorderIniKeysNeedlessly(); +#endif +#if defined(Q_OS_WIN) + void qtbug_13249(); +#endif + + void testVariantTypes_data(); + void testVariantTypes(); + void rainersSyncBugOnMac_data(); + void rainersSyncBugOnMac(); + void recursionBug(); + + void testByteArray_data(); + void testByteArray(); + +private: + void oldWriteEntry_data(); + void oldReadEntry_data(); + void oldWriteEntryHelper(QSettings &settings); + void oldReadEntryHelper(QSettings &settings); +}; + +// Testing get/set functions +void tst_QSettings::getSetCheck() +{ + QSettings obj1; + // bool QSettings::fallbacksEnabled() + // void QSettings::setFallbacksEnabled(bool) + obj1.setFallbacksEnabled(false); + QCOMPARE(false, obj1.fallbacksEnabled()); + obj1.setFallbacksEnabled(true); + QCOMPARE(true, obj1.fallbacksEnabled()); +} + +//using namespace std; + +//#include <qapplication.h> +#include <qcoreapplication.h> +#include <qdir.h> +#include <qregexp.h> +#include <qthread.h> +#include <stdlib.h> +#ifndef Q_OS_WIN +#include <unistd.h> +#endif + +Q_DECLARE_METATYPE(QSettings::Format) + +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) +static void removePath(const QString& _path) +{ + QString path = _path; + QDir dir(path); + if (!dir.exists()) + return; + QStringList entries = dir.entryList(); + foreach(QString name, entries) { + QString absolute = path + name; + if (QFileInfo(absolute).isDir()) + removePath(absolute+"\\"); + else + QFile::remove(absolute); + } + dir.cdUp(); + if (path[path.size()-1] == '\\') + path = path.left(path.size()-1); + dir.rmdir(path.mid(path.lastIndexOf('\\')+1)); +} +#endif + +static QString settingsPath(const char *path = "") +{ + // Temporary path for files that are specified explictly in the constructor. + QString tempPath = QDir::tempPath(); + if (tempPath.endsWith("/")) + tempPath.truncate(tempPath.size() - 1); + return QDir::toNativeSeparators(tempPath + "/tst_QSettings/" + QLatin1String(path)); +} + +static bool readCustom1File(QIODevice &device, QSettings::SettingsMap &map) +{ + QDataStream in(&device); + quint32 magic; + in >> magic; + in >> map; + return (magic == 0x01010101 && in.status() == QDataStream::Ok); +} + +static bool writeCustom1File(QIODevice &device, const QSettings::SettingsMap &map) +{ + QDataStream out(&device); + out << quint32(0x01010101); + out << map; + return out.status() == QDataStream::Ok; +} + +static bool readCustom2File(QIODevice &device, QSettings::SettingsMap &map) +{ + QDataStream in(&device); + quint64 magic; + in >> magic; + in >> map; + return (magic == Q_UINT64_C(0x0202020202020202) && in.status() == QDataStream::Ok); +} + +static bool writeCustom2File(QIODevice &device, const QSettings::SettingsMap &map) +{ + QDataStream out(&device); + out << Q_UINT64_C(0x0202020202020202); + out << map; + return out.status() == QDataStream::Ok; +} + +static bool readCustom3File(QIODevice &device, QSettings::SettingsMap &map) +{ + QTextStream in(&device); + QString tag; + in >> tag; + if (tag == "OK") { + map.insert("retval", "OK"); + return true; + } else { + return false; + } +} + +static bool writeCustom3File(QIODevice &device, const QSettings::SettingsMap &map) +{ + QTextStream out(&device); + if (map.value("retval") != "OK") + return false; + + out << "OK"; + return true; +} + +static void populateWithFormats() +{ + QTest::addColumn<QSettings::Format>("format"); + + QTest::newRow("native") << QSettings::NativeFormat; + QTest::newRow("ini") << QSettings::IniFormat; + QTest::newRow("custom1") << QSettings::CustomFormat1; + QTest::newRow("custom2") << QSettings::CustomFormat2; +} + +tst_QSettings::tst_QSettings() +{ + QSettings::Format custom1 = QSettings::registerFormat("custom1", readCustom1File, writeCustom1File); + QSettings::Format custom2 = QSettings::registerFormat("custom2", readCustom2File, writeCustom2File +#ifndef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER + , Qt::CaseInsensitive +#endif + ); + QVERIFY(custom1 == QSettings::CustomFormat1); + QVERIFY(custom2 == QSettings::CustomFormat2); +} + +void tst_QSettings::init() +{ + QSettings::setSystemIniPath(settingsPath("__system__")); + QSettings::setUserIniPath(settingsPath("__user__")); + +#if defined(Q_OS_WIN) + QSettings("HKEY_CURRENT_USER\\Software\\software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\other.software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\other.software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\foo", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\bar", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\bat", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\baz", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\foo", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\bar", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\bat", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\baz", QSettings::NativeFormat).clear(); + if (QDir(settingsPath()).exists()) { +#if defined(Q_OS_WINCE) + removePath(settingsPath()); +#else + if (QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) + system(QString("rmdir /Q /S %1").arg(settingsPath()).toLatin1()); + else + system(QString("deltree /Y %1").arg(settingsPath()).toLatin1()); +#endif + } +#elif defined(Q_OS_DARWIN) + QSettings(QSettings::UserScope, "software.org", "KillerAPP").clear(); + QSettings(QSettings::SystemScope, "software.org", "KillerAPP").clear(); + QSettings(QSettings::UserScope, "other.software.org", "KillerAPP").clear(); + QSettings(QSettings::SystemScope, "other.software.org", "KillerAPP").clear(); + QSettings(QSettings::UserScope, "software.org").clear(); + QSettings(QSettings::SystemScope, "software.org").clear(); + QSettings(QSettings::UserScope, "other.software.org").clear(); + QSettings(QSettings::SystemScope, "other.software.org").clear(); +#elif defined(Q_OS_SYMBIAN) + removePath(settingsPath()); +#endif + +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) + system(QString("chmod -R u+rw %1 2> /dev/null").arg(settingsPath()).toLatin1()); + system(QString("rm -fr %1 2> /dev/null").arg(settingsPath()).toLatin1()); +#endif + + QFile::remove("foo"); +} + +void tst_QSettings::cleanup() +{ + init(); +} + +/* + Test the constructors and the assignment operator. +*/ + +void tst_QSettings::ctor_data() +{ + populateWithFormats(); +} + +void tst_QSettings::ctor() +{ + QFETCH(QSettings::Format, format); + + { + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(format, QSettings::UserScope, "software.org"); + QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(format, QSettings::SystemScope, "software.org"); + + QSettings settings5(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings6(format, QSettings::UserScope, "software.org"); + QSettings settings7(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings8(format, QSettings::SystemScope, "software.org"); + + // test QSettings::format() while we're at it + QVERIFY(settings1.format() == format); + QVERIFY(settings2.format() == format); + QVERIFY(settings3.format() == format); + QVERIFY(settings4.format() == format); + + // test QSettings::scope() while we're at it + QVERIFY(settings1.scope() == QSettings::UserScope); + QVERIFY(settings2.scope() == QSettings::UserScope); + QVERIFY(settings3.scope() == QSettings::SystemScope); + QVERIFY(settings4.scope() == QSettings::SystemScope); + + // test QSettings::organizationName() while we're at it + QVERIFY(settings1.organizationName() == "software.org"); + QVERIFY(settings2.organizationName() == "software.org"); + QVERIFY(settings3.organizationName() == "software.org"); + QVERIFY(settings4.organizationName() == "software.org"); + + // test QSettings::applicationName() while we're at it + QCOMPARE(settings1.applicationName(), QString("KillerAPP")); + QVERIFY(settings2.applicationName().isEmpty()); + QVERIFY(settings3.applicationName() == "KillerAPP"); + QVERIFY(settings4.applicationName().isEmpty()); + + /* + Go forwards. + */ + settings4.setValue("key 1", QString("doodah")); + + QCOMPARE(settings1.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings3.setValue("key 1", QString("blah")); + QCOMPARE(settings1.value("key 1").toString(), QString("blah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings2.setValue("key 1", QString("whoa")); + QCOMPARE(settings1.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings1.setValue("key 1", QString("gurgle")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + /* + Test the copies. + */ + QCOMPARE(settings5.value("key 1").toString(), settings1.value("key 1").toString()); + QCOMPARE(settings6.value("key 1").toString(), settings2.value("key 1").toString()); + QCOMPARE(settings7.value("key 1").toString(), settings3.value("key 1").toString()); + QCOMPARE(settings8.value("key 1").toString(), settings4.value("key 1").toString()); + + /* + Go backwards. + */ + + settings2.setValue("key 1", QString("bilboh")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings3.setValue("key 1", QString("catha")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("catha")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings4.setValue("key 1", QString("quirko")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("catha")); + QCOMPARE(settings4.value("key 1").toString(), QString("quirko")); + + /* + Test the copies again. + */ + QCOMPARE(settings5.value("key 1").toString(), settings1.value("key 1").toString()); + QCOMPARE(settings6.value("key 1").toString(), settings2.value("key 1").toString()); + QCOMPARE(settings7.value("key 1").toString(), settings3.value("key 1").toString()); + QCOMPARE(settings8.value("key 1").toString(), settings4.value("key 1").toString()); + + /* + "General" is a problem key for .ini files. + */ + settings1.setValue("General", 1); + settings1.setValue("%General", 2); + settings1.setValue("alpha", 3); + settings1.setValue("General/alpha", 4); + settings1.setValue("%General/alpha", 5); + settings1.setValue("alpha/General", 6); + settings1.setValue("alpha/%General", 7); + settings1.setValue("General/General", 8); + settings1.setValue("General/%General", 9); + settings1.setValue("%General/General", 10); + settings1.setValue("%General/%General", 11); + } + + { + /* + Test that the data was stored on disk after all instances + of QSettings are destroyed. + */ + + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(format, QSettings::UserScope, "software.org"); + QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(format, QSettings::SystemScope, "software.org"); + + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("catha")); + QCOMPARE(settings4.value("key 1").toString(), QString("quirko")); + + /* + Test problem keys. + */ + + QCOMPARE(settings1.value("General").toInt(), 1); + QCOMPARE(settings1.value("%General").toInt(), 2); + QCOMPARE(settings1.value("alpha").toInt(), 3); + QCOMPARE(settings1.value("General/alpha").toInt(), 4); + QCOMPARE(settings1.value("%General/alpha").toInt(), 5); + QCOMPARE(settings1.value("alpha/General").toInt(), 6); + QCOMPARE(settings1.value("alpha/%General").toInt(), 7); + QCOMPARE(settings1.value("General/General").toInt(), 8); + QCOMPARE(settings1.value("General/%General").toInt(), 9); + QCOMPARE(settings1.value("%General/General").toInt(), 10); + QCOMPARE(settings1.value("%General/%General").toInt(), 11); + + /* + Test that the organization and product parameters is + case-insensitive on Windows and Mac, case-sensitive on + Unix. + */ + QSettings settings5(format, QSettings::UserScope, "SoftWare.ORG", "killerApp"); + if (format == QSettings::NativeFormat) { +#if defined(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_SYMBIAN) + QCOMPARE(settings5.value("key 1").toString(), QString("gurgle")); +#else + QVERIFY(!settings5.contains("key 1")); +#endif + } else { +#if defined(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_SYMBIAN) + QCOMPARE(settings5.value("key 1").toString(), QString("gurgle")); +#else + QVERIFY(!settings5.contains("key 1")); +#endif + } + } + + { + QSettings settings1(settingsPath("custom/custom.conf"), QSettings::IniFormat); + settings1.beginGroup("alpha/beta"); + settings1.setValue("geometry", -7); + settings1.setValue("geometry/x", 1); + settings1.setValue("geometry/y", 2); + QSettings settings2(settingsPath("custom/custom.conf"), QSettings::IniFormat); + settings1.setValue("geometry/width", 3); + settings2.setValue("alpha/beta/geometry/height", 4); + settings2.setValue("alpha/gamma/splitter", 5); + settings1.endGroup(); + + // test QSettings::scope() while we're at it + QVERIFY(settings1.scope() == QSettings::UserScope); + + // test QSettings::organizationName() while we're at it + QVERIFY(settings1.organizationName().isEmpty()); + + // test QSettings::applicationName() while we're at it + QVERIFY(settings1.organizationName().isEmpty()); + + QSettings settings3(settingsPath("custom/custom2.conf"), QSettings::IniFormat); + settings3.beginGroup("doodley/beta"); + settings3.setValue("geometry", -7); + settings3.setValue("geometry/x", 1); + settings3.setValue("geometry/y", 2); + settings3.setValue("geometry/width", 3); + settings3.setValue("geometry/height", 4); + settings3.endGroup(); + settings3.setValue("alpha/gamma/splitter", 5); + + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 5); + QCOMPARE(settings1.allKeys().count(), 6); + + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings2.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings2.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings2.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings2.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings2.value("alpha/gamma/splitter").toInt(), 5); + QCOMPARE(settings2.allKeys().count(), 6); + } + + { + QSettings settings1(settingsPath("custom/custom.conf"), QSettings::IniFormat); + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 5); + QCOMPARE(settings1.allKeys().count(), 6); + } + + { + // QSettings's default constructor is native by default + if (format == QSettings::NativeFormat) { + QCoreApplication::instance()->setOrganizationName(""); + QCoreApplication::instance()->setApplicationName(""); + QSettings settings; + QCOMPARE(settings.status(), QSettings::AccessError); + QCoreApplication::instance()->setOrganizationName("software.org"); + QCoreApplication::instance()->setApplicationName("KillerAPP"); + QSettings settings2; + QCOMPARE(settings2.status(), QSettings::NoError); + QSettings settings3("software.org", "KillerAPP"); + QCOMPARE(settings2.fileName(), settings3.fileName()); + QCoreApplication::instance()->setOrganizationName(""); + QCoreApplication::instance()->setApplicationName(""); + } + + QSettings settings(format, QSettings::UserScope, "", ""); + QCOMPARE(settings.status(), QSettings::AccessError); + QSettings settings2(format, QSettings::UserScope, "software.org", "KillerAPP"); + QCOMPARE(settings2.status(), QSettings::NoError); + + // test QSettings::format() while we're at it + QVERIFY(settings.format() == format); + QVERIFY(settings2.format() == format); + + // test QSettings::scope() while we're at it + QVERIFY(settings.scope() == QSettings::UserScope); + QVERIFY(settings2.scope() == QSettings::UserScope); + + // test QSettings::organizationName() while we're at it + QVERIFY(settings.organizationName().isEmpty()); + QVERIFY(settings2.organizationName() == "software.org"); + + // test QSettings::applicationName() while we're at it + QVERIFY(settings.applicationName().isEmpty()); + QVERIFY(settings2.applicationName() == "KillerAPP"); + } +} + +void tst_QSettings::testByteArray_data() +{ + QTest::addColumn<QByteArray>("data"); + + QByteArray bytes("Hello world!"); + + QTest::newRow("latin1") << bytes; +#ifndef QT_NO_COMPRESS + QTest::newRow("compressed") << qCompress(bytes); +#endif + QTest::newRow("with \\0") << bytes + '\0' + bytes; +} + +void tst_QSettings::testByteArray() +{ + QFETCH(QByteArray, data); + + // write + { + QSettings settings("Trolltech", "tst_qsettings"); + settings.setValue("byteArray", data); + } + // read + { + QSettings settings("Trolltech", "tst_qsettings"); + QByteArray ret = settings.value("byteArray", data).toByteArray(); + QCOMPARE(ret, data); + } +} + +void tst_QSettings::testErrorHandling_data() +{ + QTest::addColumn<int>("filePerms"); // -1 means file should not exist + QTest::addColumn<int>("dirPerms"); + QTest::addColumn<int>("statusAfterCtor"); + QTest::addColumn<bool>("shouldBeEmpty"); + QTest::addColumn<int>("statusAfterGet"); + QTest::addColumn<int>("statusAfterSetAndSync"); + + // file dir afterCtor empty afterGet afterSetAndSync + QTest::newRow("0600 0700") << 0600 << 0700 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; + + QTest::newRow("0400 0700") << 0400 << 0700 << (int)QSettings::NoError + << false << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow("0200 0700") << 0200 << 0700 << (int)QSettings::AccessError + << true << (int)QSettings::AccessError << (int)QSettings::AccessError; + + QTest::newRow(" -1 0700") << -1 << 0700 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::NoError; + + QTest::newRow(" -1 0000") << -1 << 0000 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow(" -1 0100") << -1 << 0100 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow("0600 0100") << 0600 << 0100 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; + QTest::newRow(" -1 0300") << -1 << 0300 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::NoError; + QTest::newRow("0600 0300") << 0600 << 0300 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; + QTest::newRow(" -1 0500") << -1 << 0500 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow("0600 0500") << 0600 << 0500 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; +} + +void tst_QSettings::testErrorHandling() +{ +#ifdef QT_BUILD_INTERNAL +#ifdef Q_OS_WIN + QSKIP("Windows doesn't support most file modes, including read-only directories, so this test is moot.", SkipAll); +#elif defined(Q_OS_SYMBIAN) + QSKIP("Symbian/Open C doesn't support execute or write only file modes, or directory permissions, so this test is mostly moot.", SkipAll); +#elif defined(Q_OS_UNIX) + if (::getuid() == 0) + QSKIP("Running this test as root doesn't work, since file perms do not bother him", SkipAll); +#else + QFETCH(int, filePerms); + QFETCH(int, dirPerms); + QFETCH(int, statusAfterCtor); + QFETCH(bool, shouldBeEmpty); + QFETCH(int, statusAfterGet); + QFETCH(int, statusAfterSetAndSync); + + system(QString("chmod 700 %1 2>/dev/null").arg(settingsPath("someDir")).toLatin1()); + system(QString("chmod -R u+rwx %1 2>/dev/null").arg(settingsPath("someDir")).toLatin1()); + system(QString("rm -fr %1").arg(settingsPath("someDir")).toLatin1()); + + // prepare a file with some settings + if (filePerms != -1) { + QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat); + QCOMPARE((int) settings.status(), (int) QSettings::NoError); + + settings.beginGroup("alpha/beta"); + settings.setValue("geometry", -7); + settings.setValue("geometry/x", 1); + settings.setValue("geometry/y", 2); + settings.setValue("geometry/width", 3); + settings.setValue("geometry/height", 4); + settings.endGroup(); + settings.setValue("alpha/gamma/splitter", 5); + } else { + system(QString("mkdir -p %1").arg(settingsPath("someDir")).toLatin1()); + } + + if (filePerms != -1) { + system(QString("chmod %1 %2") + .arg(QString::number(filePerms, 8)) + .arg(settingsPath("someDir/someSettings.ini")) + .toLatin1()); + } + system(QString("chmod %1 %2") + .arg(QString::number(dirPerms, 8)) + .arg(settingsPath("someDir")) + .toLatin1()); + + // the test + { + QConfFile::clearCache(); + QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat); + QCOMPARE((int)settings.status(), statusAfterCtor); + if (shouldBeEmpty) { + QCOMPARE(settings.allKeys().count(), 0); + } else { + QVERIFY(settings.allKeys().count() > 0); + } + settings.value("alpha/beta/geometry"); + QCOMPARE((int)settings.status(), statusAfterGet); + settings.setValue("alpha/beta/geometry", 100); + QCOMPARE((int)settings.status(), statusAfterGet); + QCOMPARE(settings.value("alpha/beta/geometry").toInt(), 100); + settings.sync(); + QCOMPARE(settings.value("alpha/beta/geometry").toInt(), 100); + QCOMPARE((int)settings.status(), statusAfterSetAndSync); + } +#endif // !Q_OS_WIN +#endif +} + +Q_DECLARE_METATYPE(QVariant) +Q_DECLARE_METATYPE(QSettings::Status) + +void tst_QSettings::testIniParsing_data() +{ + QTest::addColumn<QByteArray>("inicontent"); + QTest::addColumn<QString>("key"); + QTest::addColumn<QVariant>("expect"); + QTest::addColumn<QSettings::Status>("status"); + + // Test "forgiving" parsing of entries not terminated with newline or unterminated strings + QTest::newRow("good1") << QByteArray("v=1\n") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("good2") << QByteArray("v=1\\\n2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good3") << QByteArray("v=1\\\r2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good4") << QByteArray("v=1\\\n\r2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good5") << QByteArray("v=1\\\r\n2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good6") << QByteArray("v \t = \t 1\\\r\n2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("garbage1") << QByteArray("v") << "v" << QVariant() << QSettings::FormatError; + QTest::newRow("nonterm1") << QByteArray("v=str") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm2") << QByteArray("v=\"str\"") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm3") << QByteArray("v=\"str") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm4") << QByteArray("v=\\") << "v" << QVariant("") << QSettings::NoError; + QTest::newRow("nonterm5") << QByteArray("u=s\nv=\"str") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm6") << QByteArray("v=\"str\nw=ok") << "v" << QVariant("str\nw=ok") << QSettings::NoError; + QTest::newRow("nonterm7") << QByteArray("v=") << "v" << QVariant("") << QSettings::NoError; + QTest::newRow("nonterm8") << QByteArray("v=\"str\njnk") << "v" << QVariant("str\njnk") << QSettings::NoError; + QTest::newRow("nonterm9") << QByteArray("v=1\\") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm10") << QByteArray("v=1\\\n") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm11") << QByteArray("v=1\\\r") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm12") << QByteArray("v=1\\\n\r") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm13") << QByteArray("v=1\\\r\n") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm14") << QByteArray("v=1\\\n\nx=2") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm15") << QByteArray("v=1\\\r\rx=2") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm16") << QByteArray("v=1\\\n\n\nx=2") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm17") << QByteArray("; foo\nv=1") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm18") << QByteArray("; foo\n\nv=1") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm19") << QByteArray("\nv=1;foo") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm20") << QByteArray("v=x ") << "v" << QVariant("x") << QSettings::NoError; + QTest::newRow("nonterm21") << QByteArray("v=x ;") << "v" << QVariant("x") << QSettings::NoError; +} + +void tst_QSettings::testIniParsing() +{ +#ifdef QT_BUILD_INTERNAL + qRegisterMetaType<QVariant>("QVariant"); + qRegisterMetaType<QSettings::Status>("QSettings::Status"); + + QDir dir(settingsPath()); + QVERIFY(dir.mkpath("someDir")); + QFile f(dir.path()+"/someDir/someSettings.ini"); + + QFETCH(QByteArray, inicontent); + QFETCH(QString, key); + QFETCH(QVariant, expect); + QFETCH(QSettings::Status, status); + + QVERIFY(f.open(QFile::WriteOnly)); + f.write(inicontent); + f.close(); + + QConfFile::clearCache(); + QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat); + + if ( settings.status() == QSettings::NoError ) { // else no point proceeding + QVariant v = settings.value(key); + QVERIFY(v.canConvert(expect.type())); + // check some types so as to give prettier error messages + if ( v.type() == QVariant::String ) { + QCOMPARE(v.toString(), expect.toString()); + } else if ( v.type() == QVariant::Int ) { + QCOMPARE(v.toInt(), expect.toInt()); + } else { + QCOMPARE(v, expect); + } + } + + QCOMPARE(settings.status(), status); +#endif +} + +/* + Tests beginGroup(), endGroup(), and group(). +*/ +void tst_QSettings::beginGroup() +{ + QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(QSettings::UserScope, "software.org", "KillerAPP"); + + /* + Let's start with some back and forthing. + */ + + settings1.beginGroup("alpha"); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + settings1.beginGroup("/beta"); + QCOMPARE(settings1.group(), QString("beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + + settings1.beginGroup("///gamma//"); + QCOMPARE(settings1.group(), QString("gamma")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + + settings1.setValue("geometry", 5); + QCOMPARE(settings1.value("geometry").toInt(), 5); + QCOMPARE(settings1.value("/geometry///").toInt(), 5); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("/geometry///").toInt(), 5); + + /* + OK, now start for real. + */ + + settings1.beginGroup("alpha"); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setValue("geometry", 66); + QCOMPARE(settings1.value("geometry").toInt(), 66); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + + QSettings settings3(QSettings::UserScope, "software.org", "KillerAPP"); + settings3.beginGroup("alpha"); + QCOMPARE(settings3.value("geometry").toInt(), 66); + + settings1.beginGroup("/beta///"); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.setValue("geometry", 777); + QCOMPARE(settings1.value("geometry").toInt(), 777); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings3.value("geometry").toInt(), 66); + QCOMPARE(settings3.value("beta/geometry").toInt(), 777); + + settings3.beginGroup("gamma"); + settings3.setValue("geometry", 8888); + QCOMPARE(settings3.value("geometry").toInt(), 8888); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings2.value("alpha/gamma/geometry").toInt(), 8888); + QCOMPARE(settings1.value("geometry").toInt(), 777); + + // endGroup() should do nothing if group() is empty + for (int i = 0; i < 10; ++i) + settings2.endGroup(); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings2.value("alpha/gamma/geometry").toInt(), 8888); + + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + QCOMPARE(settings1.value("geometry").toInt(), 5); + QCOMPARE(settings1.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings1.value("alpha/gamma/geometry").toInt(), 8888); + + settings1.beginGroup("delta"); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup(""); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup("/"); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup("////"); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup("////omega///epsilon zeta eta theta/ / /"); + QCOMPARE(settings1.group(), QString("delta/omega/epsilon zeta eta theta/ / ")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); +} + +/* + Tests setValue() and getXxx(). +*/ +void tst_QSettings::setValue() +{ + QSettings settings(QSettings::UserScope, "software.org", "KillerAPP"); + + settings.setValue("key 2", (int)0x7fffffff); + QCOMPARE(settings.value("key 2").toInt(), (int)0x7fffffff); + QCOMPARE(settings.value("key 2").toString(), QString::number((int)0x7fffffff)); + settings.setValue("key 2", -1); + QCOMPARE(settings.value("key 2").toInt(), -1); + QCOMPARE(settings.value("key 2").toString(), QString("-1")); + settings.setValue("key 2", (int)0x80000000); + QCOMPARE(settings.value("key 2").toInt(), (int)0x80000000); + settings.setValue("key 2", (int)0); + QCOMPARE(settings.value("key 2", 123).toInt(), (int)0); + settings.setValue("key 2", (int)12345); + QCOMPARE(settings.value("key 2").toInt(), (int)12345); + QCOMPARE(settings.value("no such key", 1234).toInt(), (int)1234); + QCOMPARE(settings.value("no such key").toInt(), (int)0); + + settings.setValue("key 2", true); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", false); + QCOMPARE(settings.value("key 2", true).toBool(), false); + settings.setValue("key 2", (int)1); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", (int)-1); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", (int)0); + QCOMPARE(settings.value("key 2", true).toBool(), false); + settings.setValue("key 2", QString("true")); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", QString("false")); + QCOMPARE(settings.value("key 2", true).toBool(), false); +/* + settings.setValue("key 2", "true"); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", "false"); + QCOMPARE(settings.value("key 2", true).toBool(), false); + settings.setValue("key 2", ""); + QCOMPARE(settings.value("key 2", true).toBool(), true); + settings.setValue("key 2", ""); + QCOMPARE(settings.value("key 2", false).toBool(), false); + settings.setValue("key 2", "0.000e-00"); // cannot convert double to a bool + QCOMPARE(settings.value("key 2", true).toBool(), true); + settings.setValue("key 2", "0.000e-00"); + QCOMPARE(settings.value("key 2", false).toBool(), false); + +*/ + settings.setValue("key 2", QStringList()); + QCOMPARE(settings.value("key 2").toStringList(), QStringList()); + settings.setValue("key 2", QStringList("")); + QCOMPARE(settings.value("key 2").toStringList(), QStringList("")); + settings.setValue("key 2", QStringList() << "" << ""); + QCOMPARE(settings.value("key 2").toStringList(), QStringList() << "" << ""); + settings.setValue("key 2", QStringList() << "" << "a" << "" << "bc" << ""); + QCOMPARE(settings.value("key 2").toStringList(), QStringList() << "" << "a" << "" << "bc" << ""); + + settings.setValue("key 3", QList<QVariant>()); + QCOMPARE(settings.value("key 3").toList(), QList<QVariant>()); + settings.setValue("key 3", QList<QVariant>() << 1 << QString("a")); + QCOMPARE(settings.value("key 3").toList(), QList<QVariant>() << 1 << QString("a")); + + QList<QVariant> outerList; + outerList << 1 << QString("b"); + QList<QVariant> innerList = outerList; + outerList.append(QVariant(innerList)); + outerList.append(QVariant(innerList)); + outerList << 2 << QString("c"); + innerList = outerList; + outerList.append(QVariant(innerList)); + // outerList: [1, "b", [1, "b"], [1, "b"], 2, "c", [1, "b", [1, "b"], [1, "b"], 2, "c"]] + + settings.setValue("key 3", outerList); + QCOMPARE(settings.value("key 3").toList(), outerList); + QCOMPARE(settings.value("key 3").toList().size(), 7); + + QMap<QString, QVariant> map; + map.insert("1", "one"); + map.insert("2", "two"); + map.insert("3", outerList); + map.insert("5", "cinco"); + map.insert("10", "zehn"); + settings.setValue("key 4", map); + QCOMPARE(settings.value("key 4").toMap(), map); +} + +void tst_QSettings::testVariantTypes_data() +{ + populateWithFormats(); +} + +void tst_QSettings::testVariantTypes() +{ +#ifdef QT_BUILD_INTERNAL +#define testVal(key, val, tp, rtype) \ + { \ + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); \ + settings1.setValue(key, qVariantFromValue(val)); \ + } \ + QConfFile::clearCache(); \ + { \ + QSettings settings2(format, QSettings::UserScope, "software.org", "KillerAPP"); \ + QVariant v = settings2.value(key); \ + QVERIFY(qvariant_cast<tp >(v) == val); \ + QVERIFY(v.type() == QVariant::rtype); \ + } + + typedef QMap<QString, QVariant> TestVariantMap; + + QFETCH(QSettings::Format, format); + + TestVariantMap m2; + m2.insert("ene", "due"); + m2.insert("rike", "fake"); + m2.insert("borba", "dorba"); + testVal("key2", m2, TestVariantMap, Map); + + QStringList l2; + + l2 << "ene" << "due" << "@Point(1 2)" << "@fake"; + testVal("key3", l2, QStringList, StringList); + + l2.clear(); + l2 << "ene" << "due" << "rike" << "fake"; + testVal("key3", l2, QStringList, StringList); + + QList<QVariant> l3; + QDate date = QDate::currentDate(); + QTime time = QTime::currentTime(); + l3 << QString("ene") << 10 << qVariantFromValue(QColor(1, 2, 3)) << QVariant(QRect(1, 2, 3, 4)) + << QVariant(QSize(4, 56)) << QVariant(QPoint(4, 2)) << true << false << date << time; + testVal("key3", l3, QVariantList, List); + + testVal("key4", QString("hello"), QString, String); + testVal("key5", QColor(1, 2, 3), QColor, Color); + testVal("key6", QRect(1, 2, 3, 4), QRect, Rect); + testVal("key7", QSize(4, 56), QSize, Size); + testVal("key8", QPoint(4, 2), QPoint, Point); + testVal("key10", date, QDate, Date); + testVal("key11", time, QTime, Time); + testVal("key12", QByteArray("foo bar"), QByteArray, ByteArray); + + { + QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP"); + QVERIFY(!settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + + settings.setValue("key99", QVariant()); + QVERIFY(settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + + settings.setValue("key99", QVariant(1)); + QVERIFY(settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant(1)); + + settings.setValue("key99", QVariant()); + QVERIFY(settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + + settings.remove("key99"); + QVERIFY(!settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + } + + QList<QVariant> l4; + l4 << QVariant(m2) << QVariant(l2) << QVariant(l3); + testVal("key13", l4, QVariantList, List); + + // We store key sequences as strings instead of binary variant blob, for improved + // readability in the resulting format. + if (format >= QSettings::InvalidFormat) { + testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QKeySequence, KeySequence); + } else { + testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QString, String); + } + +#undef testVal +#endif +} + +void tst_QSettings::remove() +{ + QSettings settings0(QSettings::UserScope, "software.org", "KillerAPP"); + int initialNumKeys = settings0.allKeys().size(); + QCOMPARE(settings0.value("key 1", "123").toString(), QString("123")); + settings0.remove("key 1"); + QCOMPARE(settings0.value("key 1", "456").toString(), QString("456")); + + settings0.setValue("key 1", "bubloo"); + QCOMPARE(settings0.value("key 1").toString(), QString("bubloo")); + settings0.remove("key 2"); + QCOMPARE(settings0.value("key 1").toString(), QString("bubloo")); + settings0.remove("key 1"); + QCOMPARE(settings0.value("key 1", "789").toString(), QString("789")); + + /* + Make sure that removing a key removes all the subkeys. + */ + settings0.setValue("alpha/beta/geometry", -7); + settings0.setValue("alpha/beta/geometry/x", 1); + settings0.setValue("alpha/beta/geometry/y", 2); + settings0.setValue("alpha/beta/geometry/width", 3); + settings0.setValue("alpha/beta/geometry/height", 4); + settings0.setValue("alpha/gamma/splitter", 5); + + settings0.remove("alpha/beta/geometry/x"); + QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 999).toInt(), 999); + QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.remove("alpha/beta/geometry"); + QCOMPARE(settings0.value("alpha/beta/geometry", 777).toInt(), 777); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 111).toInt(), 111); + QCOMPARE(settings0.value("alpha/beta/geometry/y", 222).toInt(), 222); + QCOMPARE(settings0.value("alpha/beta/geometry/width", 333).toInt(), 333); + QCOMPARE(settings0.value("alpha/beta/geometry/height", 444).toInt(), 444); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.setValue("alpha/beta/geometry", -7); + settings0.setValue("alpha/beta/geometry/x", 1); + settings0.setValue("alpha/beta/geometry/y", 2); + settings0.setValue("alpha/beta/geometry/width", 3); + settings0.setValue("alpha/beta/geometry/height", 4); + settings0.setValue("alpha/gamma/splitter", 5); + QCOMPARE(settings0.allKeys().size(), initialNumKeys + 6); + + settings0.beginGroup("alpha/beta/geometry"); + settings0.remove(""); + settings0.endGroup(); + QVERIFY(!settings0.contains("alpha/beta/geometry")); + QVERIFY(!settings0.contains("alpha/beta/geometry/x")); + QVERIFY(!settings0.contains("alpha/beta/geometry/y")); + QVERIFY(!settings0.contains("alpha/beta/geometry/width")); + QVERIFY(!settings0.contains("alpha/beta/geometry/height")); + QVERIFY(settings0.contains("alpha/gamma/splitter")); + QCOMPARE(settings0.allKeys().size(), initialNumKeys + 1); + + settings0.beginGroup("alpha/beta"); + settings0.remove(""); + settings0.endGroup(); + QVERIFY(!settings0.contains("alpha/beta/geometry")); + QVERIFY(!settings0.contains("alpha/beta/geometry/x")); + QVERIFY(!settings0.contains("alpha/beta/geometry/y")); + QVERIFY(!settings0.contains("alpha/beta/geometry/width")); + QVERIFY(!settings0.contains("alpha/beta/geometry/height")); + QVERIFY(settings0.contains("alpha/gamma/splitter")); + QCOMPARE(settings0.allKeys().size(), initialNumKeys + 1); + + settings0.remove(""); + QVERIFY(!settings0.contains("alpha/gamma/splitter")); + QCOMPARE(settings0.allKeys().size(), initialNumKeys); + + /* + Do it again, but this time let's use setGroup(). + */ + + settings0.setValue("alpha/beta/geometry", -7); + settings0.setValue("alpha/beta/geometry/x", 1); + settings0.setValue("alpha/beta/geometry/y", 2); + settings0.setValue("alpha/beta/geometry/width", 3); + settings0.setValue("alpha/beta/geometry/height", 4); + settings0.setValue("alpha/gamma/splitter", 5); + + settings0.beginGroup("foo/bar/baz/doesn't"); + settings0.remove("exist"); + settings0.endGroup(); + QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings0.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.beginGroup("alpha/beta/geometry"); + settings0.remove("x"); + settings0.endGroup(); + QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 999).toInt(), 999); + QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.remove("alpha/beta"); + QCOMPARE(settings0.value("alpha/beta/geometry", 777).toInt(), 777); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 111).toInt(), 111); + QCOMPARE(settings0.value("alpha/beta/geometry/y", 222).toInt(), 222); + QCOMPARE(settings0.value("alpha/beta/geometry/width", 333).toInt(), 333); + QCOMPARE(settings0.value("alpha/beta/geometry/height", 444).toInt(), 444); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.clear(); + QCOMPARE(settings0.value("alpha/gamma/splitter", 888).toInt(), 888); + + /* + OK, now let's check what happens if settings are spread across + multiple files (user vs. global, product-specific vs. + company-wide). + */ + + QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(QSettings::UserScope, "software.org"); + QSettings settings3(QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(QSettings::SystemScope, "software.org"); + + settings4.setValue("key 1", "doodah"); + settings3.setValue("key 1", "blah"); + settings2.setValue("key 1", "whoa"); + settings1.setValue("key 1", "gurgle"); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings1.remove("key 1"); + QCOMPARE(settings1.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings2.remove("key 1"); + QCOMPARE(settings1.value("key 1").toString(), QString("blah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings3.remove("key 1"); + QCOMPARE(settings1.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings4.remove("key 1"); + QVERIFY(!settings1.contains("key 1")); + QVERIFY(!settings2.contains("key 1")); + QVERIFY(!settings3.contains("key 1")); + QVERIFY(!settings4.contains("key 1")); + + /* + Get ready for the next part of the test. + */ + + settings1.clear(); + settings2.clear(); + settings3.clear(); + settings4.clear(); + + settings1.sync(); + settings2.sync(); + settings3.sync(); + settings4.sync(); + + /* + Check that recursive removes work correctly when some of the + keys are loaded from the file and others have been modified in + memory (corresponds to originalKeys vs. addedKeys in the + QSettingsFile code). + */ + + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/gamma/splitter", 5); + settings1.sync(); + + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + + settings1.remove("alpha/beta/geometry/y"); + QVERIFY(settings1.contains("alpha/beta/geometry")); + QVERIFY(settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(settings1.contains("alpha/beta/geometry/width")); + QVERIFY(settings1.contains("alpha/beta/geometry/height")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 5); + + settings1.remove("alpha/beta/geometry/y"); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 5); + + settings1.remove("alpha/beta/geometry/height"); + QVERIFY(settings1.contains("alpha/beta/geometry")); + QVERIFY(settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(settings1.contains("alpha/beta/geometry/width")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 4); + + settings1.remove("alpha/beta/geometry"); + QVERIFY(!settings1.contains("alpha/beta/geometry")); + QVERIFY(!settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(!settings1.contains("alpha/beta/geometry/width")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height")); + QVERIFY(settings1.contains("alpha/gamma/splitter")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 1); + + settings1.sync(); + QVERIFY(!settings1.contains("alpha/beta/geometry")); + QVERIFY(!settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(!settings1.contains("alpha/beta/geometry/width")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height")); + QVERIFY(settings1.contains("alpha/gamma/splitter")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 1); +} + +/* + Tests contains() and keys(). +*/ +void tst_QSettings::contains() +{ + QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP"); + int initialNumKeys = settings1.allKeys().size(); // 0 on all platforms but Mac OS X. + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + settings1.setValue("alpha/gamma/splitter", 5); + settings1.setValue("alpha/gamma/splitter/ /", 5); + + QVERIFY(!settings1.contains("alpha")); + QVERIFY(!settings1.contains("alpha/beta")); + QVERIFY(!settings1.contains("///alpha///beta///")); + QVERIFY(settings1.contains("alpha/beta/geometry")); + QVERIFY(settings1.contains("///alpha///beta//geometry//")); + QVERIFY(settings1.contains("alpha/beta/geometry/x")); + QVERIFY(settings1.contains("alpha/beta/geometry/y")); + QVERIFY(settings1.contains("alpha/beta/geometry/width")); + QVERIFY(settings1.contains("alpha/beta/geometry/height")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height/foo/bar/doesn't/exist")); + QVERIFY(!settings1.contains("alpha/gamma")); + QVERIFY(settings1.contains("alpha/gamma/splitter")); + QVERIFY(settings1.contains("alpha/gamma/splitter/ ")); + QVERIFY(settings1.contains("////alpha/gamma/splitter// ////")); + + settings1.beginGroup("alpha"); + QVERIFY(!settings1.contains("beta")); + QVERIFY(!settings1.contains("/////beta///")); + QVERIFY(settings1.contains("beta/geometry")); + QVERIFY(settings1.contains("/////beta//geometry//")); + QVERIFY(settings1.contains("beta/geometry/x")); + QVERIFY(settings1.contains("beta/geometry/y")); + QVERIFY(settings1.contains("beta/geometry/width")); + QVERIFY(settings1.contains("beta/geometry/height")); + QVERIFY(!settings1.contains("beta/geometry/height/foo/bar/doesn't/exist")); + QVERIFY(!settings1.contains("gamma")); + QVERIFY(settings1.contains("gamma/splitter")); + QVERIFY(settings1.contains("gamma/splitter/ ")); + QVERIFY(settings1.contains("////gamma/splitter// ////")); + + settings1.beginGroup("beta/geometry"); + QVERIFY(settings1.contains("x")); + QVERIFY(settings1.contains("y")); + QVERIFY(settings1.contains("width")); + QVERIFY(settings1.contains("height")); + QVERIFY(!settings1.contains("height/foo/bar/doesn't/exist")); + + QStringList keys = settings1.allKeys(); + QStringList expectedResult = QStringList() << "x" << "y" << "width" << "height"; + keys.sort(); + expectedResult.sort(); + int i; + QCOMPARE(keys, expectedResult); + for (i = 0; i < keys.size(); ++i) { + QVERIFY(settings1.contains(keys.at(i))); + } + + settings1.endGroup(); + QVERIFY(settings1.group() == "alpha"); + keys = settings1.allKeys(); + QCOMPARE(keys.size(), expectedResult.size() + 3); + for (i = 0; i < keys.size(); ++i) { + QVERIFY(settings1.contains(keys.at(i))); + } + + settings1.endGroup(); + QVERIFY(settings1.group().isEmpty()); + keys = settings1.allKeys(); + + QCOMPARE(keys.size(), initialNumKeys + 7); + for (i = 0; i < keys.size(); ++i) { + QVERIFY(settings1.contains(keys.at(i))); + } +} + +void tst_QSettings::sync() +{ + /* + What we're trying to test here is the case where two + instances of the same application access the same preference + files. We want to make sure that the results are 'merged', + rather than having the last application overwrite settings + set by the first application (like in Qt 3). + + This is only applicable to the INI format. The Windows + registry and Mac's CFPreferences API should take care of this + by themselves. + */ + + QSettings settings1(QSettings::IniFormat, QSettings::UserScope, "software.org"); + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + settings1.setValue("alpha/gamma/splitter", 5); + settings1.sync(); // and it all goes into the file + + QSettings settings2(QSettings::IniFormat, QSettings::UserScope, "other.software.org"); + settings2.setValue("alpha/beta/geometry/x", 8); + settings2.sync(); + + settings2.setValue("moo/beta/geometry", -7); + settings2.setValue("moo/beta/geometry/x", 1); + settings2.setValue("moo/beta/geometry/y", 2); + settings2.setValue("moo/beta/geometry/width", 3); + settings2.setValue("moo/beta/geometry/height", 4); + settings2.setValue("moo/gamma/splitter", 5); + settings2.setValue("alpha/gamma/splitter", 15); + settings2.remove("alpha/beta/geometry/x"); + settings2.remove("alpha/beta/geometry/y"); // should do nothing + + // Now "some other app" will change other.software.org.ini + QString userConfDir = settingsPath("__user__") + QDir::separator(); +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + unlink((userConfDir + "other.software.org.ini").toLatin1()); + rename((userConfDir + "software.org.ini").toLatin1(), + (userConfDir + "other.software.org.ini").toLatin1()); +#else + QFile::remove(userConfDir + "other.software.org.ini"); + QFile::rename(userConfDir + "software.org.ini" , userConfDir + "other.software.org.ini"); +#endif + + settings2.sync(); + + // And voila, we should be merged + + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), -7); + QVERIFY(!settings2.contains("alpha/beta/geometry/x")); // <----- removed by settings2 + QCOMPARE(settings2.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings2.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings2.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings2.value("alpha/gamma/splitter").toInt(), 15); // <---- set by settings2 + QCOMPARE(settings2.value("moo/beta/geometry").toInt(), -7); + QCOMPARE(settings2.value("moo/beta/geometry/x").toInt(), 1); + QCOMPARE(settings2.value("moo/beta/geometry/y").toInt(), 2); + QCOMPARE(settings2.value("moo/beta/geometry/width").toInt(), 3); + QCOMPARE(settings2.value("moo/beta/geometry/height").toInt(), 4); + QCOMPARE(settings2.value("moo/gamma/splitter").toInt(), 5); + QCOMPARE(settings2.allKeys().count(), 11); + + // Now, software.org.ini no longer exists, this is same as another app + // clearing all settings. + settings1.sync(); + QCOMPARE(settings1.allKeys().count(), 0); + +/* + // Now "some other app" will change software.org.conf + unlink((userConfDir + "software.org.ini").toLatin1()); + rename((userConfDir + "other.software.org.ini").toLatin1(), + (userConfDir + "software.org.ini").toLatin1()); + + settings1.sync(); + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 15); + QCOMPARE(settings1.value("moo/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("moo/beta/geometry/x").toInt(), 1); + QCOMPARE(settings1.value("moo/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("moo/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("moo/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("moo/gamma/splitter").toInt(), 5); + QCOMPARE(settings1.allKeys().count(), 11); +*/ +} + +void tst_QSettings::setFallbacksEnabled_data() +{ + populateWithFormats(); +} + +void tst_QSettings::setFallbacksEnabled() +{ + QFETCH(QSettings::Format, format); + + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(format, QSettings::UserScope, "software.org"); + QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(format, QSettings::SystemScope, "software.org"); + + settings1.setValue("key 1", "alpha"); + settings2.setValue("key 1", "beta"); + settings3.setValue("key 1", "gamma"); + settings4.setValue("key 1", "delta"); + + settings1.setValue("key 2", "alpha"); + settings2.setValue("key 2", "beta"); + settings3.setValue("key 2", "gamma"); + + settings1.setValue("key 3", "alpha"); + settings3.setValue("key 3", "gamma"); + settings4.setValue("key 3", "delta"); + + settings1.setValue("key 4", "alpha"); + settings2.setValue("key 4", "beta"); + settings4.setValue("key 4", "delta"); + + settings2.setValue("key 5", "beta"); + settings3.setValue("key 5", "gamma"); + settings4.setValue("key 5", "delta"); + + QVERIFY(settings1.fallbacksEnabled()); + QVERIFY(settings2.fallbacksEnabled()); + QVERIFY(settings3.fallbacksEnabled()); + QVERIFY(settings4.fallbacksEnabled()); + + settings1.setFallbacksEnabled(false); + settings2.setFallbacksEnabled(false); + settings3.setFallbacksEnabled(false); + settings4.setFallbacksEnabled(false); + + QVERIFY(!settings1.fallbacksEnabled()); + QVERIFY(!settings2.fallbacksEnabled()); + QVERIFY(!settings3.fallbacksEnabled()); + QVERIFY(!settings4.fallbacksEnabled()); + + /* + Make sure that the QSettings objects can still access their + main associated file when fallbacks are turned off. + */ + + QCOMPARE(settings1.value("key 1").toString(), QString("alpha")); + QCOMPARE(settings2.value("key 1").toString(), QString("beta")); + QCOMPARE(settings3.value("key 1").toString(), QString("gamma")); + QCOMPARE(settings4.value("key 1").toString(), QString("delta")); + + QCOMPARE(settings1.value("key 2").toString(), QString("alpha")); + QCOMPARE(settings2.value("key 2").toString(), QString("beta")); + QCOMPARE(settings3.value("key 2").toString(), QString("gamma")); + QVERIFY(!settings4.contains("key 2")); + + QCOMPARE(settings1.value("key 3").toString(), QString("alpha")); + QCOMPARE(settings3.value("key 3").toString(), QString("gamma")); + QCOMPARE(settings4.value("key 3").toString(), QString("delta")); + QVERIFY(!settings2.contains("key 3")); + + QCOMPARE(settings1.value("key 4").toString(), QString("alpha")); + QCOMPARE(settings2.value("key 4").toString(), QString("beta")); + QCOMPARE(settings4.value("key 4").toString(), QString("delta")); + QVERIFY(!settings3.contains("key 4")); + + QCOMPARE(settings2.value("key 5").toString(), QString("beta")); + QCOMPARE(settings3.value("key 5").toString(), QString("gamma")); + QCOMPARE(settings4.value("key 5").toString(), QString("delta")); + QVERIFY(!settings1.contains("key 5")); + + QCOMPARE(settings1.value("key 1").toString(), QString("alpha")); + QCOMPARE(settings1.value("key 5").toString(), QString("")); + QVERIFY(settings1.contains("key 1")); + QVERIFY(!settings1.contains("key 5")); +} + +void tst_QSettings::testChildKeysAndGroups_data() +{ + populateWithFormats(); +} + +void tst_QSettings::testChildKeysAndGroups() +{ + QFETCH(QSettings::Format, format); + + QSettings settings1(format, QSettings::UserScope, "software.org"); + settings1.setFallbacksEnabled(false); + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + settings1.setValue("alpha/gamma/splitter", 5); + + QCOMPARE(settings1.childKeys(), QStringList()); + QCOMPARE(settings1.childGroups(), QStringList() << "alpha"); + + settings1.beginGroup("/alpha"); + QCOMPARE(settings1.childKeys(), QStringList()); + QCOMPARE(settings1.childGroups(), QStringList() << "beta" << "gamma"); + + settings1.beginGroup("/beta"); + QCOMPARE(settings1.childKeys(), QStringList() << "geometry"); + QCOMPARE(settings1.childGroups(), QStringList() << "geometry"); + + settings1.beginGroup("/geometry"); + QCOMPARE(settings1.childKeys(), QStringList() << "height" << "width" << "x" << "y"); + QCOMPARE(settings1.childGroups(), QStringList()); + + settings1.beginGroup("/width"); + QCOMPARE(settings1.childKeys(), QStringList()); + QCOMPARE(settings1.childGroups(), QStringList()); + + settings1.endGroup(); + settings1.endGroup(); + settings1.endGroup(); + settings1.endGroup(); + + { // task 53792 + QSettings settings2("other.software.org"); + settings2.setValue("viewbar/foo/test1", "1"); + settings2.setValue("viewbar/foo/test2", "2"); + settings2.setValue("viewbar/foo/test3", "3"); + settings2.setValue("viewbar/foo/test4", "4"); + settings2.setValue("viewbar/foo/test5", "5"); + settings2.setValue("viewbar/bar/test1", "1"); + settings2.setValue("viewbar/bar/test2", "2"); + settings2.setValue("viewbar/bar/test3", "3"); + settings2.setValue("viewbar/bar/test4", "4"); + settings2.setValue("viewbar/bar/test5", "5"); + + settings2.beginGroup("viewbar"); + QStringList l = settings2.childGroups(); + settings2.endGroup(); + l.sort(); + QCOMPARE(l, QStringList() << "bar" << "foo"); + } +} + +void tst_QSettings::testUpdateRequestEvent() +{ + QFile::remove("foo"); + QVERIFY(!QFile::exists("foo")); + + QSettings settings1("foo", QSettings::IniFormat); + QVERIFY(!QFile::exists("foo")); + QVERIFY(QFileInfo("foo").size() == 0); + settings1.setValue("key1", 1); + QVERIFY(QFileInfo("foo").size() == 0); + + QTRY_VERIFY(QFileInfo("foo").size() > 0); + + settings1.remove("key1"); + QVERIFY(QFileInfo("foo").size() > 0); + + QTRY_VERIFY(QFileInfo("foo").size() == 0); + + settings1.setValue("key2", 2); + QVERIFY(QFileInfo("foo").size() == 0); + + QTRY_VERIFY(QFileInfo("foo").size() > 0); + + settings1.clear(); + QVERIFY(QFileInfo("foo").size() > 0); + + QTRY_VERIFY(QFileInfo("foo").size() == 0); +} + +const int NumIterations = 5; +const int NumThreads = 4; + +class SettingsThread : public QThread +{ +public: + void run(); + void start(int n) { param = n; QThread::start(); } + +private: + int param; +}; + +void SettingsThread::run() +{ + for (int i = 0; i < NumIterations; ++i) { + QSettings settings("software.org", "KillerAPP"); + settings.setValue(QString::number((param * NumIterations) + i), param); + settings.sync(); + QCOMPARE((int)settings.status(), (int)QSettings::NoError); + } +} + +void tst_QSettings::testThreadSafety() +{ + SettingsThread threads[NumThreads]; + int i, j; + + for (i = 0; i < NumThreads; ++i) + threads[i].start(i + 1); + for (i = 0; i < NumThreads; ++i) + threads[i].wait(); + + QSettings settings("software.org", "KillerAPP"); + for (i = 0; i < NumThreads; ++i) { + int param = i + 1; + for (j = 0; j < NumIterations; ++j) { + QCOMPARE(settings.value(QString::number((param * NumIterations) + j)).toInt(), param); + } + } +} + +void tst_QSettings::testNormalizedKey_data() +{ + QTest::addColumn<QString>("inKey"); + QTest::addColumn<QString>("outKey"); + + QTest::newRow("empty1") << "" << ""; + QTest::newRow("empty2") << "/" << ""; + QTest::newRow("empty3") << "//" << ""; + QTest::newRow("empty4") << "///" << ""; + + QTest::newRow("a1") << "a" << "a"; + QTest::newRow("a2") << "/a" << "a"; + QTest::newRow("a3") << "a/" << "a"; + QTest::newRow("a4") << "//a" << "a"; + QTest::newRow("a5") << "a//" << "a"; + QTest::newRow("a6") << "///a" << "a"; + QTest::newRow("a7") << "a///" << "a"; + QTest::newRow("a8") << "///a/" << "a"; + QTest::newRow("a9") << "/a///" << "a"; + + QTest::newRow("ab1") << "aaa/bbb" << "aaa/bbb"; + QTest::newRow("ab2") << "/aaa/bbb" << "aaa/bbb"; + QTest::newRow("ab3") << "aaa/bbb/" << "aaa/bbb"; + QTest::newRow("ab4") << "/aaa/bbb/" << "aaa/bbb"; + QTest::newRow("ab5") << "aaa///bbb" << "aaa/bbb"; + QTest::newRow("ab6") << "aaa///bbb/" << "aaa/bbb"; + QTest::newRow("ab7") << "/aaa///bbb/" << "aaa/bbb"; + QTest::newRow("ab8") << "////aaa///bbb////" << "aaa/bbb"; +} + +void tst_QSettings::testNormalizedKey() +{ +#ifdef QT_BUILD_INTERNAL + QFETCH(QString, inKey); + QFETCH(QString, outKey); + + inKey.detach(); + + QString result = QSettingsPrivate::normalizedKey(inKey); + QCOMPARE(result, outKey); + + /* + If the key is already normalized, we verify that outKey is + just a shallow copy of the input string. This is an important + optimization that shouldn't be removed accidentally. + */ + if (inKey == outKey) { + QVERIFY(!result.isDetached()); + } else { + if (!result.isEmpty()) { + QVERIFY(result.isDetached()); + } + } +#endif +} + +void tst_QSettings::testEmptyData() +{ + QString filename(QDir::tempPath() + "/empty.ini"); + QFile::remove(filename); + QVERIFY(!QFile::exists(filename)); + + QString nullString; + QString emptyString(""); + QStringList emptyList; + QStringList list; + QStringList list2; + + QVariantList emptyVList; + QVariantList vList, vList2, vList3; + + list << emptyString << nullString; + list2 << emptyString; + vList << emptyString; + vList2 << emptyString << nullString; + vList3 << QString("foo"); + + { + QSettings settings(filename, QSettings::IniFormat); + settings.setValue("nullString", nullString); + settings.setValue("emptyString", emptyString); + settings.setValue("emptyList", emptyList); + settings.setValue("list", list); + settings.setValue("list2", list2); + settings.setValue("emptyVList", emptyVList); + settings.setValue("vList", vList); + settings.setValue("vList2", vList2); + settings.setValue("vList3", vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + { + QSettings settings(filename, QSettings::IniFormat); + QCOMPARE(settings.value("nullString").toString(), nullString); + QCOMPARE(settings.value("emptyString").toString(), emptyString); + QCOMPARE(settings.value("emptyList").toStringList(), emptyList); + QCOMPARE(settings.value("list").toStringList(), list); + QCOMPARE(settings.value("list2").toStringList(), list2); + QCOMPARE(settings.value("emptyVList").toList(), emptyVList); + QCOMPARE(settings.value("vList").toList(), vList); + QCOMPARE(settings.value("vList2").toList(), vList2); + QCOMPARE(settings.value("vList3").toList(), vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + + { + QSettings settings("Trolltech", "tst_qsettings"); + settings.setValue("nullString", nullString); + settings.setValue("emptyString", emptyString); + settings.setValue("emptyList", emptyList); + settings.setValue("list", list); + settings.setValue("list2", list2); + settings.setValue("emptyVList", emptyVList); + settings.setValue("vList", vList); + settings.setValue("vList2", vList2); + settings.setValue("vList3", vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + { + QSettings settings("Trolltech", "tst_qsettings"); + QCOMPARE(settings.value("nullString").toString(), nullString); + QCOMPARE(settings.value("emptyString").toString(), emptyString); + QCOMPARE(settings.value("emptyList").toStringList(), emptyList); + QCOMPARE(settings.value("list").toStringList(), list); + QCOMPARE(settings.value("list2").toStringList(), list2); + QCOMPARE(settings.value("emptyVList").toList(), emptyVList); + QCOMPARE(settings.value("vList").toList(), vList); + QCOMPARE(settings.value("vList2").toList(), vList2); + QCOMPARE(settings.value("vList3").toList(), vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + QFile::remove(filename); +} + +void tst_QSettings::testResourceFiles() +{ + QSettings settings(":/resourcefile.ini", QSettings::IniFormat); + QVERIFY(settings.status() == QSettings::NoError); + QVERIFY(!settings.isWritable()); + QCOMPARE(settings.value("Field 1/Bottom").toInt(), 89); + settings.setValue("Field 1/Bottom", 90); + + // the next two lines check the statu quo; another behavior would be possible + QVERIFY(settings.status() == QSettings::NoError); + QCOMPARE(settings.value("Field 1/Bottom").toInt(), 90); + + settings.sync(); + QVERIFY(settings.status() == QSettings::AccessError); + QCOMPARE(settings.value("Field 1/Bottom").toInt(), 90); +} + +void tst_QSettings::fromFile_data() +{ + populateWithFormats(); +} + +void tst_QSettings::fromFile() +{ + QFETCH(QSettings::Format, format); + + QFile::remove("foo"); + QVERIFY(!QFile::exists("foo")); + + QString path = "foo"; + +#ifdef Q_OS_WIN + if (format == QSettings::NativeFormat) + path = "\\HKEY_CURRENT_USER\\Software\\foo"; +#endif + + QStringList strList = QStringList() << "hope" << "destiny" << "chastity"; + + { + QSettings settings1(path, format); + QVERIFY(settings1.allKeys().isEmpty()); + + settings1.setValue("alpha", 1); + settings1.setValue("alpha", 2); + settings1.setValue("beta", strList); + + QSettings settings2(path, format); + QCOMPARE(settings2.value("alpha").toInt(), 2); + + settings1.sync(); +#ifndef Q_OS_WIN + QVERIFY(QFile::exists("foo")); +#endif + QCOMPARE(settings1.value("alpha").toInt(), 2); + QCOMPARE(settings2.value("alpha").toInt(), 2); + + settings2.setValue("alpha", 3); + settings2.setValue("gamma/foo.bar", 4); + QCOMPARE(settings1.value("alpha").toInt(), 3); + QCOMPARE(settings2.value("alpha").toInt(), 3); + QCOMPARE(settings1.value("beta").toStringList(), strList); + QCOMPARE(settings2.value("beta").toStringList(), strList); + QCOMPARE(settings1.value("gamma/foo.bar").toInt(), 4); + QCOMPARE(settings2.value("gamma/foo.bar").toInt(), 4); + } + + { + QSettings settings1(path, format); + QCOMPARE(settings1.value("alpha").toInt(), 3); + QCOMPARE(settings1.value("beta").toStringList(), strList); + QCOMPARE(settings1.value("gamma/foo.bar").toInt(), 4); + QCOMPARE(settings1.allKeys().size(), 3); + } +} + +void tst_QSettings::setIniCodec() +{ +#ifdef QT_BUILD_INTERNAL + QByteArray expeContents4, expeContents5; + QByteArray actualContents4, actualContents5; + + { + QFile inFile(":/resourcefile4.ini"); + inFile.open(QIODevice::ReadOnly); + expeContents4 = inFile.readAll(); + inFile.close(); + } + + { + QFile inFile(":/resourcefile5.ini"); + inFile.open(QIODevice::ReadOnly); + expeContents5 = inFile.readAll(); + inFile.close(); + } + + { + QSettings settings4(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + settings4.setIniCodec("UTF-8"); + settings4.setValue(QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"), QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC")); + settings4.sync(); + + QSettings settings5(QSettings::IniFormat, QSettings::UserScope, "other.software.org", "KillerAPP"); + settings5.setIniCodec("ISO 8859-1"); + settings5.setValue(QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"), QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC")); + settings5.sync(); + + { + QFile inFile(settings4.fileName()); + inFile.open(QIODevice::ReadOnly); + actualContents4 = inFile.readAll(); + inFile.close(); + } + + { + QFile inFile(settings5.fileName()); + inFile.open(QIODevice::ReadOnly); + actualContents5 = inFile.readAll(); + inFile.close(); + } + } + + QConfFile::clearCache(); + + QCOMPARE(actualContents4, expeContents4); + QCOMPARE(actualContents5, expeContents5); + + QSettings settings4(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + settings4.setIniCodec("UTF-8"); + QSettings settings5(QSettings::IniFormat, QSettings::UserScope, "other.software.org", "KillerAPP"); + settings5.setIniCodec("Latin-1"); + + QCOMPARE(settings4.allKeys().count(), 1); + QCOMPARE(settings5.allKeys().count(), 1); + + QCOMPARE(settings4.allKeys().first(), settings5.allKeys().first()); + QCOMPARE(settings4.value(settings4.allKeys().first()).toString(), + settings5.value(settings5.allKeys().first()).toString()); +#endif +} + +static bool containsSubList(QStringList mom, QStringList son) +{ + for (int i = 0; i < son.size(); ++i) { + if (!mom.contains(son.at(i))) + return false; + } + return true; +} + +void tst_QSettings::testArrays_data() +{ + populateWithFormats(); +} + +/* + Tests beginReadArray(), beginWriteArray(), endArray(), and + setArrayIndex(). +*/ +void tst_QSettings::testArrays() +{ + QFETCH(QSettings::Format, format); + + { + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + + settings1.beginWriteArray("foo/bar", 3); + settings1.setValue("bip", 1); + settings1.setArrayIndex(0); + settings1.setValue("ene", 2); + settings1.setValue("due", 3); + settings1.setValue("rike", 4); + settings1.setArrayIndex(1); + settings1.setValue("ene", 5); + settings1.setValue("due", 6); + settings1.setValue("rike", 7); + settings1.setArrayIndex(2); + settings1.setValue("ene", 8); + settings1.setValue("due", 9); + settings1.setValue("rike", 10); + settings1.endArray(); + + QStringList expectedList; + expectedList + << "foo/bar/bip" + << "foo/bar/size" + << "foo/bar/1/ene" + << "foo/bar/1/due" + << "foo/bar/1/rike" + << "foo/bar/2/ene" + << "foo/bar/2/due" + << "foo/bar/2/rike" + << "foo/bar/3/ene" + << "foo/bar/3/due" + << "foo/bar/3/rike"; + expectedList.sort(); + + QStringList actualList = settings1.allKeys(); + actualList.sort(); + QVERIFY(containsSubList(actualList, expectedList)); + + QCOMPARE(settings1.value("/foo/bar/bip").toInt(), 1); + QCOMPARE(settings1.value("/foo/bar/1/ene").toInt(), 2); + QCOMPARE(settings1.value("/foo/bar/1/due").toInt(), 3); + QCOMPARE(settings1.value("/foo/bar/1/rike").toInt(), 4); + QCOMPARE(settings1.value("/foo/bar/2/ene").toInt(), 5); + QCOMPARE(settings1.value("/foo/bar/2/due").toInt(), 6); + QCOMPARE(settings1.value("/foo/bar/2/rike").toInt(), 7); + QCOMPARE(settings1.value("/foo/bar/3/ene").toInt(), 8); + QCOMPARE(settings1.value("/foo/bar/3/due").toInt(), 9); + QCOMPARE(settings1.value("/foo/bar/3/rike").toInt(), 10); + + settings1.beginGroup("/foo"); + int count = settings1.beginReadArray("bar"); + QCOMPARE(count, 3); + QCOMPARE(settings1.value("bip").toInt(), 1); + settings1.setArrayIndex(0); + QCOMPARE(settings1.value("ene").toInt(), 2); + QCOMPARE(settings1.value("due").toInt(), 3); + QCOMPARE(settings1.value("rike").toInt(), 4); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(1); + QCOMPARE(settings1.value("ene").toInt(), 5); + QCOMPARE(settings1.value("due").toInt(), 6); + QCOMPARE(settings1.value("rike").toInt(), 7); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(2); + QCOMPARE(settings1.value("ene").toInt(), 8); + QCOMPARE(settings1.value("due").toInt(), 9); + QCOMPARE(settings1.value("rike").toInt(), 10); + QCOMPARE(settings1.allKeys().count(), 3); + + settings1.endArray(); + settings1.endGroup(); + } + /* + Check that we get the arrays right when we load them again + */ + + { + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + + QStringList expectedList; + expectedList + << "foo/bar/bip" + << "foo/bar/size" + << "foo/bar/1/ene" + << "foo/bar/1/due" + << "foo/bar/1/rike" + << "foo/bar/2/ene" + << "foo/bar/2/due" + << "foo/bar/2/rike" + << "foo/bar/3/ene" + << "foo/bar/3/due" + << "foo/bar/3/rike"; + expectedList.sort(); + + QStringList actualList = settings1.allKeys(); + actualList.sort(); + QVERIFY(containsSubList(actualList, expectedList)); + + QCOMPARE(settings1.value("/foo/bar/bip").toInt(), 1); + QCOMPARE(settings1.value("/foo/bar/1/ene").toInt(), 2); + QCOMPARE(settings1.value("/foo/bar/1/due").toInt(), 3); + QCOMPARE(settings1.value("/foo/bar/1/rike").toInt(), 4); + QCOMPARE(settings1.value("/foo/bar/2/ene").toInt(), 5); + QCOMPARE(settings1.value("/foo/bar/2/due").toInt(), 6); + QCOMPARE(settings1.value("/foo/bar/2/rike").toInt(), 7); + QCOMPARE(settings1.value("/foo/bar/3/ene").toInt(), 8); + QCOMPARE(settings1.value("/foo/bar/3/due").toInt(), 9); + QCOMPARE(settings1.value("/foo/bar/3/rike").toInt(), 10); + + settings1.beginGroup("/foo"); + int count = settings1.beginReadArray("bar"); + QCOMPARE(count, 3); + QCOMPARE(settings1.value("bip").toInt(), 1); + settings1.setArrayIndex(0); + QCOMPARE(settings1.value("ene").toInt(), 2); + QCOMPARE(settings1.value("due").toInt(), 3); + QCOMPARE(settings1.value("rike").toInt(), 4); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(1); + QCOMPARE(settings1.value("ene").toInt(), 5); + QCOMPARE(settings1.value("due").toInt(), 6); + QCOMPARE(settings1.value("rike").toInt(), 7); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(2); + QCOMPARE(settings1.value("ene").toInt(), 8); + QCOMPARE(settings1.value("due").toInt(), 9); + QCOMPARE(settings1.value("rike").toInt(), 10); + QCOMPARE(settings1.allKeys().count(), 3); + + settings1.endArray(); + settings1.endGroup(); + } + /* + This code generates lots of warnings, but that's on purpose. + Basically, we check that endGroup() can be used instead of + endArray() and vice versa. This is not documented, but this + is the behavior that we have chosen. + */ + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + settings1.clear(); + settings1.beginGroup("/alpha"); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setArrayIndex(0); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setArrayIndex(1); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setArrayIndex(2); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.beginGroup("/beta"); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.beginGroup(""); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.beginWriteArray("DO", 4); + QCOMPARE(settings1.value("size").toInt(), 4); + QCOMPARE(settings1.group(), QString("alpha/beta/DO")); + settings1.setArrayIndex(0); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/1")); + settings1.setArrayIndex(1); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2")); + settings1.beginGroup("1"); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.setArrayIndex(3); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.setArrayIndex(4); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.beginWriteArray("RE"); + QVERIFY(!settings1.contains("size")); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE")); + settings1.setArrayIndex(0); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE/1")); + settings1.setArrayIndex(1); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE/2")); + settings1.endArray(); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.endArray(); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2")); + settings1.setArrayIndex(2); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/3")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.endArray(); + QCOMPARE(settings1.group(), QString()); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + + /* + Now, let's make sure that things work well if an array + is spread across multiple files. + */ + int i; + + settings1.clear(); + QSettings settings2(format, QSettings::UserScope, "software.org"); + + QStringList threeStrings; + threeStrings << "Uno" << "Dos" << "Tres"; + + QStringList fiveStrings; + fiveStrings << "alpha" << "beta" << "gamma" << "delta" << "epsilon"; + + settings1.beginWriteArray("strings"); + for (i = threeStrings.size() - 1; i >= 0; --i) { + settings1.setArrayIndex(i); + settings1.setValue("fileName", threeStrings.at(i)); + } + settings1.endArray(); + + settings2.beginWriteArray("strings"); + for (i = fiveStrings.size() - 1; i >= 0; --i) { + settings2.setArrayIndex(i); + settings2.setValue("fileName", fiveStrings.at(i)); + } + settings2.endArray(); + + int size1 = settings1.beginReadArray("strings"); + QCOMPARE(size1, 3); + QCOMPARE(settings1.value("size").toInt(), 3); + + for (i = 0; i < size1; ++i) { + settings1.setArrayIndex(i); + QString str = settings1.value("fileName").toString(); + QCOMPARE(str, threeStrings.at(i)); + } + settings1.endArray(); + + int size2 = settings2.beginReadArray("strings"); + QCOMPARE(size2, 5); + QCOMPARE(settings2.value("size").toInt(), 5); + + for (i = 0; i < size2; ++i) { + settings2.setArrayIndex(i); + QString str = settings2.value("fileName").toString(); + QCOMPARE(str, fiveStrings.at(i)); + } + settings2.endArray(); + + size1 = settings1.beginReadArray("strings"); + QCOMPARE(size1, 3); + + // accessing entries beyond the end of settings1 goes to settings2 + for (i = size1; i < size2; ++i) { + settings1.setArrayIndex(i); + QString str = settings1.value("fileName").toString(); + QCOMPARE(str, fiveStrings.at(i)); + } + settings1.endArray(); +} + +#ifdef QT_BUILD_INTERNAL +static QByteArray iniEscapedKey(const QString &str) +{ + QByteArray result; + QSettingsPrivate::iniEscapedKey(str, result); + return result; +} + +static QString iniUnescapedKey(const QByteArray &ba) +{ + QString result; + QSettingsPrivate::iniUnescapedKey(ba, 0, ba.size(), result); + return result; +} + +static QByteArray iniEscapedStringList(const QStringList &strList) +{ + QByteArray result; + QSettingsPrivate::iniEscapedStringList(strList, result, 0); + return result; +} + +static QStringList iniUnescapedStringList(const QByteArray &ba) +{ + QStringList result; + QString str; +#if QSETTINGS_P_H_VERSION >= 2 + bool isStringList = QSettingsPrivate::iniUnescapedStringList(ba, 0, ba.size(), str, result +#if QSETTINGS_P_H_VERSION >= 3 + , 0 +#endif + ); + if (!isStringList) + result = QStringList(str); +#else + QStringList *strList = QSettingsPrivate::iniUnescapedStringList(ba, 0, ba.size(), str); + if (strList) { + result = *strList; + delete strList; + } else { + result = QStringList(str); + } +#endif + return result; +} +#endif + +QString escapeWeirdChars(const QString &s) +{ + QString result; + bool escapeNextDigit = false; + + for (int i = 0; i < s.length(); ++i) { + QChar c = s.at(i); + if (c.unicode() < ' ' || c.unicode() > '~' + || (escapeNextDigit && c.unicode() >= '0' && c.unicode() <= 'f')) { + result += QString("\\x%1").arg(c.unicode(), 0, 16); + escapeNextDigit = true; + } else { + result += c; + escapeNextDigit = false; + } + } + + return result; +} + +void tst_QSettings::testEscapes() +{ +#ifdef QT_BUILD_INTERNAL + QSettings settings(QSettings::UserScope, "software.org", "KillerAPP"); + +#define testEscapedKey(plainKey, escKey) \ + QCOMPARE(iniEscapedKey(plainKey), QByteArray(escKey)); \ + QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); + +#define testUnescapedKey(escKey, plainKey, reescKey) \ + QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); \ + QCOMPARE(iniEscapedKey(plainKey), QByteArray(reescKey)); \ + QCOMPARE(iniUnescapedKey(reescKey), QString(plainKey)); + +#define testEscapedStringList(plainStrList, escStrList) \ + { \ + QStringList plainList(plainStrList); \ + QByteArray escList(escStrList); \ + QCOMPARE(iniEscapedStringList(plainList), escList); \ + QCOMPARE(iniUnescapedStringList(escList), plainList); \ + } \ + + +#define testUnescapedStringList(escStrList, plainStrList, reescStrList) \ + { \ + QStringList plainList(plainStrList); \ + QByteArray escList(escStrList); \ + QByteArray reescList(reescStrList); \ + QCOMPARE(iniUnescapedStringList(escList), plainList); \ + QCOMPARE(iniEscapedStringList(plainList), reescList); \ + QCOMPARE(iniUnescapedStringList(reescList), plainList); \ + } \ + + +#define testVariant(val, escStr, func) \ + { \ + QVariant v(val); \ + QString s = QSettingsPrivate::variantToString(v); \ + /*qDebug() << QString("testVariant(): reference=\"%1\" result=\"%2\"").arg(escStr).arg(s); */\ + QCOMPARE(s, escStr); \ + QCOMPARE(QVariant(QSettingsPrivate::stringToVariant(escStr)), v); \ + QVERIFY(val == v.func()); \ + } + +#define testBadEscape(escStr, vStr) \ + { \ + QVariant v = QSettingsPrivate::stringToVariant(QString(escStr)); \ + QCOMPARE(v.toString(), QString(vStr)); \ + } + + testEscapedKey("", ""); + testEscapedKey(" ", "%20"); + testEscapedKey(" 0123 abcd ", "%200123%20abcd%20"); + testEscapedKey("~!@#$%^&*()_+.-/\\=", "%7E%21%40%23%24%25%5E%26%2A%28%29_%2B.-\\%5C%3D"); + testEscapedKey(QString() + QChar(0xabcd) + QChar(0x1234) + QChar(0x0081), "%UABCD%U1234%81"); + testEscapedKey(QString() + QChar(0xFE) + QChar(0xFF) + QChar(0x100) + QChar(0x101), "%FE%FF%U0100%U0101"); + + testUnescapedKey("", "", ""); + testUnescapedKey("%20", " ", "%20"); + testUnescapedKey("/alpha/beta", "/alpha/beta", "\\alpha\\beta"); + testUnescapedKey("\\alpha\\beta", "/alpha/beta", "\\alpha\\beta"); + testUnescapedKey("%5Calpha%5Cbeta", "\\alpha\\beta", "%5Calpha%5Cbeta"); + testUnescapedKey("%", "%", "%25"); + testUnescapedKey("%f%!%%%%1x%x1%U%Uz%U123%U1234%1234%", QString("%f%!%%%%1x%x1%U%Uz%U123") + QChar(0x1234) + "\x12" + "34%", + "%25f%25%21%25%25%25%251x%25x1%25U%25Uz%25U123%U1234%1234%25"); + + testEscapedStringList("", ""); + testEscapedStringList(" ", "\" \""); + testEscapedStringList(";", "\";\""); + testEscapedStringList(",", "\",\""); + testEscapedStringList("=", "\"=\""); + testEscapedStringList("abc-def", "abc-def"); + testEscapedStringList(QChar(0) + QString("0"), "\\0\\x30"); + testEscapedStringList("~!@#$%^&*()_+.-/\\=", "\"~!@#$%^&*()_+.-/\\\\=\""); + testEscapedStringList("~!@#$%^&*()_+.-/\\", "~!@#$%^&*()_+.-/\\\\"); + testEscapedStringList(QString("\x7F") + "12aFz", "\\x7f\\x31\\x32\\x61\\x46z"); + testEscapedStringList(QString(" \t\n\\n") + QChar(0x123) + QChar(0x4567), "\" \\t\\n\\\\n\\x123\\x4567\""); + testEscapedStringList(QString("\a\b\f\n\r\t\v'\"?\001\002\x03\x04"), "\\a\\b\\f\\n\\r\\t\\v'\\\"?\\x1\\x2\\x3\\x4"); + testEscapedStringList(QStringList() << "," << ";" << "a" << "ab, \tc, d ", "\",\", \";\", a, \"ab, \\tc, d \""); + + /* + Test .ini syntax that cannot be generated by QSettings (but can be entered by users). + */ + testUnescapedStringList("", "", ""); + testUnescapedStringList("\"\"", "", ""); + testUnescapedStringList("\"abcdef\"", "abcdef", "abcdef"); + testUnescapedStringList("\"\\?\\'\\\"\"", "?'\"", "?'\\\""); + testUnescapedStringList("\\0\\00\\000\\0000000\\1\\111\\11111\\x\\x0\\xABCDEFGH\\x0123456\\", + QString() + QChar(0) + QChar(0) + QChar(0) + QChar(0) + QChar(1) + + QChar(0111) + QChar(011111) + QChar(0) + QChar(0xCDEF) + "GH" + + QChar(0x3456), + "\\0\\0\\0\\0\\x1I\\x1249\\0\\xcdefGH\\x3456"); + testUnescapedStringList(QByteArray("\\c\\d\\e\\f\\g\\$\\*\\\0", 16), "\f", "\\f"); + testUnescapedStringList("\"a\", \t\"bc \", \" d\" , \"ef \" ,,g, hi i,,, ,", + QStringList() << "a" << "bc " << " d" << "ef " << "" << "g" << "hi i" + << "" << "" << "" << "", + "a, \"bc \", \" d\", \"ef \", , g, hi i, , , , "); + testUnescapedStringList("a , b , c d , efg ", + QStringList() << "a" << "b" << "c d" << "efg", + "a, b, c d, efg"); + + // streaming qvariant into a string + testVariant(QString("Hello World!"), QString("Hello World!"), toString); + testVariant(QString("Hello, World!"), QString("Hello, World!"), toString); + testVariant(QString("@Hello World!"), QString("@@Hello World!"), toString); + testVariant(QString("@@Hello World!"), QString("@@@Hello World!"), toString); + testVariant(QByteArray("Hello World!"), QString("@ByteArray(Hello World!)"), toString); + testVariant(QByteArray("@Hello World!"), QString("@ByteArray(@Hello World!)"), toString); + testVariant(QVariant(100), QString("100"), toString); + testVariant(QStringList() << "ene" << "due" << "rike", QString::fromLatin1("@Variant(\x0\x0\x0\xb\x0\x0\x0\x3\x0\x0\x0\x6\x0\x65\x0n\x0\x65\x0\x0\x0\x6\x0\x64\x0u\x0\x65\x0\x0\x0\x8\x0r\x0i\x0k\x0\x65)", 50), toStringList); + testVariant(QRect(1, 2, 3, 4), QString("@Rect(1 2 3 4)"), toRect); + testVariant(QSize(5, 6), QString("@Size(5 6)"), toSize); + testVariant(QPoint(7, 8), QString("@Point(7 8)"), toPoint); + + testBadEscape("", ""); + testBadEscape("@", "@"); + testBadEscape("@@", "@"); + testBadEscape("@@@", "@@"); + testBadEscape(" ", " "); + testBadEscape("@Rect", "@Rect"); + testBadEscape("@Rect(", "@Rect("); + testBadEscape("@Rect()", "@Rect()"); + testBadEscape("@Rect)", "@Rect)"); + testBadEscape("@Rect(1 2 3)", "@Rect(1 2 3)"); + testBadEscape("@@Rect(1 2 3)", "@Rect(1 2 3)"); +#endif +} + +void tst_QSettings::testCaseSensitivity_data() +{ + populateWithFormats(); +} + +void tst_QSettings::testCaseSensitivity() +{ + QFETCH(QSettings::Format, format); + + for (int pass = 0; pass < 2; ++pass) { + QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP"); + settings.beginGroup("caseSensitivity"); + + bool cs = true; +#ifndef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER + switch (format) { + case QSettings::NativeFormat: +#ifdef Q_OS_DARWIN + cs = true; +#else + cs = false; +#endif + break; + case QSettings::IniFormat: + cs = false; + break; + case QSettings::CustomFormat1: + cs = true; + break; + case QSettings::CustomFormat2: + cs = false; + break; + default: + ; + } +#endif + + if (pass == 0) { + settings.setValue("key 1", 1); + settings.setValue("KEY 1", 2); + settings.setValue("key 2", 3); + } + + for (int i = 0; i < 2; ++i) { + QVERIFY(settings.contains("key 1")); + QVERIFY(settings.contains("KEY 1")); + QCOMPARE(settings.value("KEY 1").toInt(), 2); +/* QVERIFY(settings.allKeys().contains("/KEY 1")); + QVERIFY(settings.allKeys().contains("/key 2")); */ + + if (cs) { + QVERIFY(!settings.contains("kEy 1")); + QCOMPARE(settings.value("key 1").toInt(), 1); + QCOMPARE(settings.allKeys().size(), 3); + QVERIFY(settings.allKeys().contains("key 1")); + } else { + QVERIFY(settings.contains("kEy 1")); + QCOMPARE(settings.value("kEy 1").toInt(), 2); + QCOMPARE(settings.value("key 1").toInt(), 2); + QCOMPARE(settings.allKeys().size(), 2); + } + + settings.sync(); + } + + settings.remove("KeY 1"); + + if (cs) { + QVERIFY(!settings.contains("KeY 1")); + QVERIFY(settings.contains("key 1")); + QVERIFY(settings.contains("KEY 1")); + QCOMPARE(settings.value("key 1").toInt(), 1); + QCOMPARE(settings.value("KEY 1").toInt(), 2); + QCOMPARE(settings.allKeys().size(), 3); + } else { + QVERIFY(!settings.contains("KeY 1")); + QVERIFY(!settings.contains("key 1")); + QVERIFY(!settings.contains("KEY 1")); + QCOMPARE(settings.allKeys().size(), 1); + } + settings.setValue("KEY 1", 2); + } +} + +void tst_QSettings::fileName() +{ +#ifdef Q_OS_MAC + QSettings s1(QSettings::UserScope, "Apple", "Console"); + QSettings s2(QSettings::UserScope, "Apple"); + QSettings s3(QSettings::SystemScope, "Apple", "Console"); + QSettings s4(QSettings::SystemScope, "Apple"); + + QCOMPARE(s1.fileName(), QDir::homePath() + "/Library/Preferences/com.apple.Console.plist"); + QCOMPARE(s2.fileName(), QDir::homePath() + "/Library/Preferences/com.apple.plist"); + QCOMPARE(s3.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + QCOMPARE(s4.fileName(), QString("/Library/Preferences/com.apple.plist")); + + QSettings s5(QSettings::SystemScope, "Apple.com", "Console"); + QCOMPARE(s5.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s6(QSettings::SystemScope, "apple.com", "Console"); + QCOMPARE(s6.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s7(QSettings::SystemScope, "apple.Com", "Console"); + QCOMPARE(s7.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s8(QSettings::SystemScope, "apple.fr", "Console"); + QCOMPARE(s8.fileName(), QString("/Library/Preferences/fr.apple.Console.plist")); + + QSettings s9(QSettings::SystemScope, "apple.co.jp", "Console"); + QCOMPARE(s9.fileName(), QString("/Library/Preferences/jp.co.apple.Console.plist")); + + QSettings s10(QSettings::SystemScope, "apple.org", "Console"); + QCOMPARE(s10.fileName(), QString("/Library/Preferences/org.apple.Console.plist")); + + QSettings s11(QSettings::SystemScope, "apple.net", "Console"); + QCOMPARE(s11.fileName(), QString("/Library/Preferences/net.apple.Console.plist")); + + QSettings s12(QSettings::SystemScope, "apple.museum", "Console"); + QCOMPARE(s12.fileName(), QString("/Library/Preferences/museum.apple.Console.plist")); + + QSettings s13(QSettings::SystemScope, "apple.FR", "Console"); + QCOMPARE(s13.fileName(), QString("/Library/Preferences/fr.apple.Console.plist")); + + QSettings s14(QSettings::SystemScope, "apple.mUseum", "Console"); + QCOMPARE(s14.fileName(), QString("/Library/Preferences/museum.apple.Console.plist")); + + QSettings s15(QSettings::SystemScope, "apple.zz", "Console"); + QCOMPARE(s15.fileName(), QString("/Library/Preferences/zz.apple.Console.plist")); + + QSettings s15_prime(QSettings::SystemScope, "apple.foo", "Console"); + QCOMPARE(s15_prime.fileName(), QString("/Library/Preferences/com.apple-foo.Console.plist")); + + QSettings s16(QSettings::SystemScope, "apple.f", "Console"); + QCOMPARE(s16.fileName(), QString("/Library/Preferences/com.apple-f.Console.plist")); + + QSettings s17(QSettings::SystemScope, "apple.", "Console"); + QCOMPARE(s17.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s18(QSettings::SystemScope, "Foo, Inc.", "Console"); + QCOMPARE(s18.fileName(), QString("/Library/Preferences/com.foo-inc.Console.plist")); + + QSettings s19(QSettings::SystemScope, "Foo, Inc.com", "Console"); + QCOMPARE(s19.fileName(), QString("/Library/Preferences/com.foo, inc.Console.plist")); + + QSettings s20(QSettings::SystemScope, QLatin1String(" ") + QChar(0xbd) + QLatin1String("Foo//:/Barxxx Baz!()#@.com"), "Console"); + QCOMPARE(s20.fileName(), QLatin1String("/Library/Preferences/com. ") + QChar(0xbd) + QLatin1String("foo : barxxx baz!()#@.Console.plist")); + + QSettings s21(QSettings::SystemScope, QLatin1String(" ") + QChar(0xbd) + QLatin1String("Foo//:/Bar,,, Baz!()#"), "Console"); + QCOMPARE(s21.fileName(), QString("/Library/Preferences/com.foo-bar-baz.Console.plist")); +#else + QSKIP("Please write a fileName() test for the other platforms", SkipAll); +#endif +} + +void tst_QSettings::isWritable_data() +{ + populateWithFormats(); +} + +void tst_QSettings::isWritable() +{ + QFETCH(QSettings::Format, format); + + { + QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP"); + s1.setValue("foo", 1); + s1.sync(); + // that should create the file + } + + { + QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QVERIFY(s1.isWritable()); + } + + { + QSettings s1(format, QSettings::SystemScope, "software.org", "KillerAPP"); + s1.setValue("foo", 1); + s1.sync(); + // that should create the file, *if* we have the permissions + } + + { + QSettings s1(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings s2(format, QSettings::SystemScope, "software.org", "Something Different"); + QSettings s3(format, QSettings::SystemScope, "foo.org", "Something Different"); + if (s1.contains("foo")) { + QVERIFY(s1.isWritable()); + QVERIFY(s2.isWritable()); + QVERIFY(s3.isWritable()); + } else { + QVERIFY(!s1.isWritable()); + QVERIFY(!s2.isWritable()); + QVERIFY(!s3.isWritable()); + } + } +} + +void tst_QSettings::childGroups_data() +{ + populateWithFormats(); +} + +void tst_QSettings::childGroups() +{ +#ifdef QT_BUILD_INTERNAL + QFETCH(QSettings::Format, format); + + { + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setValue("alpha", "1"); + settings.setValue("alpha/a", "2"); + settings.setValue("alpha/b", "3"); + settings.setValue("alpha/c", "4"); + settings.setValue("beta", "5"); + settings.setValue("gamma", "6"); + settings.setValue("gamma/d", "7"); + settings.setValue("gamma/d/e", "8"); + settings.setValue("gamma/f/g", "9"); + settings.setValue("omicron/h/i/j/x", "10"); + settings.setValue("omicron/h/i/k/y", "11"); + settings.setValue("zeta/z", "12"); + } + + for (int pass = 0; pass < 3; ++pass) { + QConfFile::clearCache(); + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setFallbacksEnabled(false); + if (pass == 1) { + settings.value("gamma/d"); + } else if (pass == 2) { + settings.value("gamma"); + } + + settings.beginGroup("gamma"); + QCOMPARE(settings.childGroups(), QStringList() << "d" << "f"); + settings.beginGroup("d"); + QCOMPARE(settings.childGroups(), QStringList()); + settings.endGroup(); + settings.endGroup(); + + settings.beginGroup("alpha"); + QCOMPARE(settings.childGroups(), QStringList()); + settings.endGroup(); + + settings.beginGroup("d"); + QCOMPARE(settings.childGroups(), QStringList()); + settings.endGroup(); + + settings.beginGroup("/omicron///h/i///"); + QCOMPARE(settings.childGroups(), QStringList() << "j" << "k"); + settings.endGroup(); + + settings.beginGroup("////"); + QCOMPARE(settings.childGroups(), QStringList() << "alpha" << "gamma" << "omicron" << "zeta"); + settings.endGroup(); + + QCOMPARE(settings.childGroups(), QStringList() << "alpha" << "gamma" << "omicron" << "zeta"); + } +#endif +} + +void tst_QSettings::childKeys_data() +{ + populateWithFormats(); +} + +void tst_QSettings::childKeys() +{ +#ifdef QT_BUILD_INTERNAL + QFETCH(QSettings::Format, format); + + { + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setValue("alpha", "1"); + settings.setValue("alpha/a", "2"); + settings.setValue("alpha/b", "3"); + settings.setValue("alpha/c", "4"); + settings.setValue("beta", "5"); + settings.setValue("gamma", "6"); + settings.setValue("gamma/d", "7"); + settings.setValue("gamma/d/e", "8"); + settings.setValue("gamma/f/g", "9"); + settings.setValue("omicron/h/i/j/x", "10"); + settings.setValue("omicron/h/i/k/y", "11"); + settings.setValue("zeta/z", "12"); + } + + for (int pass = 0; pass < 3; ++pass) { + QConfFile::clearCache(); + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setFallbacksEnabled(false); + if (pass == 1) { + settings.value("gamma/d"); + } else if (pass == 2) { + settings.value("gamma"); + } + + settings.beginGroup("gamma"); + QCOMPARE(settings.childKeys(), QStringList() << "d"); + settings.beginGroup("d"); + QCOMPARE(settings.childKeys(), QStringList() << "e"); + settings.endGroup(); + settings.endGroup(); + + settings.beginGroup("alpha"); + QCOMPARE(settings.childKeys(), QStringList() << "a" << "b" << "c"); + settings.endGroup(); + + settings.beginGroup("d"); + QCOMPARE(settings.childKeys(), QStringList()); + settings.endGroup(); + + settings.beginGroup("/omicron///h/i///"); + QCOMPARE(settings.childKeys(), QStringList()); + settings.endGroup(); + + settings.beginGroup("////"); + QCOMPARE(settings.childKeys(), QStringList() << "alpha" << "beta" << "gamma"); + settings.endGroup(); + + QCOMPARE(settings.childKeys(), QStringList() << "alpha" << "beta" << "gamma"); + } +#endif +} + +void tst_QSettings::allKeys_data() +{ + populateWithFormats(); +} + +void tst_QSettings::allKeys() +{ +#ifdef QT_BUILD_INTERNAL + QFETCH(QSettings::Format, format); + + QStringList allKeys; + allKeys << "alpha" << "alpha/a" << "alpha/b" << "alpha/c" << "beta" << "gamma" << "gamma/d" + << "gamma/d/e" << "gamma/f/g" << "omicron/h/i/j/x" << "omicron/h/i/k/y" << "zeta/z"; + + { + QSettings settings(format, QSettings::SystemScope, "software.org"); + for (int i = 0; i < allKeys.size(); ++i) + settings.setValue(allKeys.at(i), QString::number(i + 1)); + } + + for (int pass = 0; pass < 3; ++pass) { + QConfFile::clearCache(); + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setFallbacksEnabled(false); + + if (pass == 1) { + settings.value("gamma/d"); + } else if (pass == 2) { + settings.value("gamma"); + } + + settings.beginGroup("gamma"); + QCOMPARE(settings.allKeys(), QStringList() << "d" << "d/e" << "f/g"); + settings.beginGroup("d"); + QCOMPARE(settings.allKeys(), QStringList() << "e"); + settings.endGroup(); + settings.endGroup(); + + settings.beginGroup("alpha"); + QCOMPARE(settings.allKeys(), QStringList() << "a" << "b" << "c"); + settings.endGroup(); + + settings.beginGroup("d"); + QCOMPARE(settings.allKeys(), QStringList()); + settings.endGroup(); + + settings.beginGroup("/omicron///h/i///"); + QCOMPARE(settings.allKeys(), QStringList() << "j/x" << "k/y"); + settings.endGroup(); + + settings.beginGroup("////"); + QCOMPARE(settings.allKeys(), allKeys); + settings.endGroup(); + + QCOMPARE(settings.allKeys(), allKeys); + } +#endif +} + +void tst_QSettings::registerFormat() +{ + QSettings settings1(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(QSettings::CustomFormat1, QSettings::UserScope, "software.org", "KillerAPP"); + + QString fileName = settings1.fileName(); + fileName.chop(3); // "ini"; + fileName.append("custom1"); + QCOMPARE(settings2.fileName(), fileName); + + // OK, let's see if it can read a generated file of a custom type + // Beware: readCustom3File() and writeCustom3File() have unintuitive behavior + // so we can test error handling + + QSettings::Format custom3 = QSettings::registerFormat("custom3", readCustom3File, writeCustom3File); + QVERIFY(custom3 == QSettings::CustomFormat3); + + QDir dir(settingsPath()); + QVERIFY(dir.mkpath("someDir")); + QFile f(dir.path()+"/someDir/someSettings.custom3"); + + QVERIFY(f.open(QFile::WriteOnly)); + f.write("OK"); + f.close(); + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3); + QCOMPARE(settings.status(), QSettings::NoError); + QCOMPARE(settings.value("retval").toString(), QString("OK")); + QVERIFY(settings.isWritable()); + } + + QVERIFY(f.open(QFile::WriteOnly)); + f.write("NotOK"); + f.close(); + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3); + QCOMPARE(settings.status(), QSettings::FormatError); + QCOMPARE(settings.value("retval").toString(), QString()); + QVERIFY(settings.isWritable()); + } + + QVERIFY(f.open(QFile::WriteOnly)); + f.write("OK"); + f.close(); + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3); + QCOMPARE(settings.status(), QSettings::NoError); + settings.setValue("zzz", "bar"); + settings.sync(); + QCOMPARE(settings.status(), QSettings::NoError); + + settings.setValue("retval", "NotOK"); + settings.sync(); + QCOMPARE(settings.status(), QSettings::AccessError); + + QCOMPARE(settings.value("retval").toString(), QString("NotOK")); + QVERIFY(settings.isWritable()); + } + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat4); + QCOMPARE(settings.status(), QSettings::AccessError); + QVERIFY(!settings.isWritable()); + } +} + +void tst_QSettings::setPath() +{ +#define TEST_PATH(doSet, ext, format, scope, path) \ + { \ + if (doSet) \ + QSettings::setPath(QSettings::format, QSettings::scope, settingsPath(path)); \ + QSettings settings1(QSettings::format, QSettings::scope, "software.org", "KillerAPP"); \ + QCOMPARE(QDir(settings1.fileName()), QDir(settingsPath(path) + QDir::separator() + "software.org" \ + + QDir::separator() + "KillerAPP." + ext)); \ + } + + /* + The first pass checks that setPath() works; the second + path checks that it has no bad side effects. + */ + for (int i = 0; i < 2; ++i) { +#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) + TEST_PATH(i == 0, "conf", NativeFormat, UserScope, "alpha") + TEST_PATH(i == 0, "conf", NativeFormat, SystemScope, "beta") +#endif + TEST_PATH(i == 0, "ini", IniFormat, UserScope, "gamma") + TEST_PATH(i == 0, "ini", IniFormat, SystemScope, "omicron") + TEST_PATH(i == 0, "custom1", CustomFormat1, UserScope, "epsilon") + TEST_PATH(i == 0, "custom1", CustomFormat1, SystemScope, "zeta") + TEST_PATH(i == 0, "custom2", CustomFormat2, UserScope, "eta") + TEST_PATH(i == 0, "custom2", CustomFormat2, SystemScope, "iota") + } +} + +void tst_QSettings::setDefaultFormat() +{ + QVERIFY(QSettings::defaultFormat() == QSettings::NativeFormat); + + QSettings::setDefaultFormat(QSettings::CustomFormat1); + QSettings settings1("org", "app"); + QSettings settings2(QSettings::SystemScope, "org", "app"); + QSettings settings3; + + QVERIFY(settings1.format() == QSettings::NativeFormat); + QVERIFY(settings2.format() == QSettings::NativeFormat); + QVERIFY(settings3.format() == QSettings::CustomFormat1); + + QSettings::setDefaultFormat(QSettings::NativeFormat); + QVERIFY(QSettings::defaultFormat() == QSettings::NativeFormat); + + QVERIFY(settings1.format() == QSettings::NativeFormat); + QVERIFY(settings2.format() == QSettings::NativeFormat); + QVERIFY(settings3.format() == QSettings::CustomFormat1); +} + +void tst_QSettings::dontCreateNeedlessPaths() +{ + QString path; + { + QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Hello", "Test"); + QVariant val = settings.value("foo", "bar"); + path = settings.fileName(); + } + + QFileInfo fileInfo(path); + QVERIFY(!fileInfo.dir().exists()); +} + +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) +void tst_QSettings::dontReorderIniKeysNeedlessly() +{ +#ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER + QSKIP("This Qt build does not preserve ordering, as a code size optimization.", SkipAll); +#endif + + /* + This is a very strong test. It asserts that modifying + resourcefile2.ini will lead to the exact contents of + resourcefile3.ini. Right now it's run only on Unix + systems, but that should be enough since the INI + code (unlike this test) is platform-agnostic. + + Things that are tested: + + * keys are written in the same order that they were + read in + + * new keys are put at the end of their respective + sections + */ + + QFile inFile(":/resourcefile2.ini"); + inFile.open(QIODevice::ReadOnly); + QByteArray contentsBefore = inFile.readAll(); + inFile.close(); + + QByteArray expectedContentsAfter; + + { + QFile inFile(":/resourcefile3.ini"); + inFile.open(QIODevice::ReadOnly); + expectedContentsAfter = inFile.readAll(); + inFile.close(); + } + + QString outFileName; + QString outFileName2; + + QTemporaryFile outFile; + outFile.open(); + outFile.write(contentsBefore); + outFileName = outFile.fileName(); + outFile.close(); + + QSettings settings(outFileName, QSettings::IniFormat); + QVERIFY(settings.status() == QSettings::NoError); + QVERIFY(settings.isWritable()); + + settings.setValue("Field 1/Bottom", 90); + settings.setValue("Field 1/x", 1); + settings.setValue("Field 1/y", 1); + settings.setValue("Field 1/width", 1); + settings.setValue("Field 1/height", 1); + settings.sync(); + + QFile outFile2(outFileName); + QVERIFY(outFile2.open(QIODevice::ReadOnly)); + QCOMPARE(outFile2.readAll(), expectedContentsAfter); + outFile2.close(); +} +#endif + +void tst_QSettings::rainersSyncBugOnMac_data() +{ + ctor_data(); +} + +void tst_QSettings::rainersSyncBugOnMac() +{ + QFETCH(QSettings::Format, format); + + QString fileName; + + { + QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QCOMPARE(s1.value("key1", 5).toInt(), 5); + fileName = s1.fileName(); + } + + { + QSettings s2(fileName, format); + s2.setValue("key1", 25); + } + + { + QSettings s3(format, QSettings::UserScope, "software.org", "KillerAPP"); + QCOMPARE(s3.value("key1", 30).toInt(), 25); + } +} + +void tst_QSettings::recursionBug() +{ + QPixmap pix(10,10); + pix.fill("blue"); + + { + QSettings settings(settingsPath("starrunner.ini"), QSettings::IniFormat); + settings.setValue("General/Pixmap", pix ); + } +} + +#if defined(Q_OS_WIN) + +static DWORD readKeyType(HKEY handle, const QString &rSubKey) +{ + DWORD dataType; + DWORD dataSize; + LONG res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()), 0, &dataType, 0, &dataSize); + + if (res == ERROR_SUCCESS) + return dataType; + + return 0; +} + +void tst_QSettings::qtbug_13249() +{ + QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP"); + + qint32 x = 1024; + settings1.setValue("qtbug_13249_a", (qint32)x); + QCOMPARE(settings1.value("qtbug_13249_a").toInt(), (qint32)1024); + settings1.setValue("qtbug_13249_b", (quint32)x); + QCOMPARE(settings1.value("qtbug_13249_b").toUInt(), (quint32)1024); + settings1.setValue("qtbug_13249_c", (qint64)x); + QCOMPARE(settings1.value("qtbug_13249_c").toLongLong(), (qint64)1024); + settings1.setValue("qtbug_13249_d", (quint64)x); + QCOMPARE(settings1.value("qtbug_13249_d").toULongLong(), (quint64)1024); + settings1.sync(); + + HKEY handle; + LONG res; + QString keyName = "Software\\software.org\\KillerAPP"; + res = RegOpenKeyEx(HKEY_CURRENT_USER, reinterpret_cast<const wchar_t *>(keyName.utf16()), 0, KEY_READ, &handle); + if (res == ERROR_SUCCESS) + { + DWORD dataType; + dataType = readKeyType(handle, QString("qtbug_13249_a")); + if (dataType != 0) { + QCOMPARE((int)REG_DWORD, (int)dataType); + } + dataType = readKeyType(handle, QString("qtbug_13249_b")); + if (dataType != 0) { + QCOMPARE((int)REG_DWORD, (int)dataType); + } + dataType = readKeyType(handle, QString("qtbug_13249_c")); + if (dataType != 0) { + QCOMPARE((int)REG_QWORD, (int)dataType); + } + dataType = readKeyType(handle, QString("qtbug_13249_d")); + if (dataType != 0) { + QCOMPARE((int)REG_QWORD, (int)dataType); + } + RegCloseKey(handle); + } +} +#endif +/* +// Not tested at the moment. +void tst_QSettings::oldSubkeyList() +{ + QVERIFY( TRUE ); +} +*/ + +QTEST_MAIN(tst_QSettings) +#include "tst_qsettings.moc" + + +// foo diff --git a/tests/auto/corelib/io/qtemporaryfile/.gitignore b/tests/auto/corelib/io/qtemporaryfile/.gitignore new file mode 100644 index 0000000000..67cb8bf69e --- /dev/null +++ b/tests/auto/corelib/io/qtemporaryfile/.gitignore @@ -0,0 +1 @@ +tst_qtemporaryfile diff --git a/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro b/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro new file mode 100644 index 0000000000..64a043b19a --- /dev/null +++ b/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro @@ -0,0 +1,14 @@ +load(qttest_p4) +SOURCES += tst_qtemporaryfile.cpp +QT = core + + +symbian { + testData.files = tst_qtemporaryfile.cpp + testData.path = . + DEPLOYMENT += testData +}else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp new file mode 100644 index 0000000000..2edb93aee2 --- /dev/null +++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp @@ -0,0 +1,729 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qcoreapplication.h> +#include <qstring.h> +#include <qtemporaryfile.h> +#include <qfile.h> +#include <qdir.h> +#include <qset.h> + +#if defined(Q_OS_WIN) +# include <windows.h> +#endif +#if defined(Q_OS_UNIX) +# include <sys/types.h> +# include <sys/stat.h> +# include <errno.h> +# include <fcntl.h> // open(2) +# include <unistd.h> // close(2) +#endif + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "" +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QTemporaryFile : public QObject +{ + Q_OBJECT +public: + tst_QTemporaryFile(); + virtual ~tst_QTemporaryFile(); +public slots: + void init(); + void cleanup(); + + void initTestCase(); + void cleanupTestCase(); + +private slots: + void construction(); + void fileTemplate(); + void fileTemplate_data(); + void getSetCheck(); + void fileName(); + void fileNameIsEmpty(); + void autoRemove(); + void write(); + void openCloseOpenClose(); + void size(); + void resize(); + void openOnRootDrives(); + void stressTest(); + void rename(); + void renameFdLeak(); + void reOpenThroughQFile(); + void keepOpenMode(); + void resetTemplateAfterError(); + void setTemplateAfterOpen(); + void autoRemoveAfterFailedRename(); + + void QTBUG_4796_data(); + void QTBUG_4796(); + +public: +}; + +void tst_QTemporaryFile::initTestCase() +{ + // For QTBUG_4796 + QVERIFY(QDir("test-XXXXXX").exists() || QDir().mkdir("test-XXXXXX")); +} + +void tst_QTemporaryFile::cleanupTestCase() +{ + // From QTBUG_4796 + QVERIFY(QDir().rmdir("test-XXXXXX")); +} + +void tst_QTemporaryFile::construction() +{ + QTemporaryFile file(0); + QString tmp = QDir::tempPath(); + QCOMPARE(file.fileTemplate().left(tmp.size()), tmp); + QCOMPARE(file.fileTemplate().at(tmp.size()), QChar('/')); +} + +// Testing get/set functions +void tst_QTemporaryFile::getSetCheck() +{ + QTemporaryFile obj1; + // bool QTemporaryFile::autoRemove() + // void QTemporaryFile::setAutoRemove(bool) + obj1.setAutoRemove(false); + QCOMPARE(false, obj1.autoRemove()); + obj1.setAutoRemove(true); + QCOMPARE(true, obj1.autoRemove()); +} + +tst_QTemporaryFile::tst_QTemporaryFile() +{ +} + +tst_QTemporaryFile::~tst_QTemporaryFile() +{ + +} + +void tst_QTemporaryFile::init() +{ +// TODO: Add initialization code here. +// This will be executed immediately before each test is run. +} + +void tst_QTemporaryFile::cleanup() +{ +// TODO: Add cleanup code here. +// This will be executed immediately after each test is run. +} + +void tst_QTemporaryFile::fileTemplate_data() +{ + QTest::addColumn<QString>("constructorTemplate"); + QTest::addColumn<QString>("prefix"); + QTest::addColumn<QString>("suffix"); + QTest::addColumn<QString>("fileTemplate"); + + QTest::newRow("constructor default") << "" << "." << "" << ""; + QTest::newRow("constructor with xxx sufix") << "qt_XXXXXXxxx" << "qt_" << "xxx" << ""; + QTest::newRow("constructor with xXx sufix") << "qt_XXXXXXxXx" << "qt_" << "xXx" << ""; + QTest::newRow("constructor with no sufix") << "qt_XXXXXX" << "qt_" << "" << ""; + QTest::newRow("constructor with >6 X's and xxx suffix") << "qt_XXXXXXXXXXxxx" << "qt_" << "xxx" << ""; + QTest::newRow("constructor with >6 X's, no suffix") << "qt_XXXXXXXXXX" << "qt_" << "" << ""; + + QTest::newRow("constructor with XXXX suffix") << "qt_XXXXXX_XXXX" << "qt_" << "_XXXX" << ""; + QTest::newRow("constructor with XXXXX suffix") << "qt_XXXXXX_XXXXX" << "qt_" << "_XXXXX" << ""; + QTest::newRow("constructor with XXXX prefix") << "qt_XXXX" << "qt_XXXX." << "" << ""; + QTest::newRow("constructor with XXXXX prefix") << "qt_XXXXX" << "qt_XXXXX." << "" << ""; + QTest::newRow("constructor with XXXX prefix and suffix") << "qt_XXXX_XXXXXX_XXXX" << "qt_XXXX_" << "_XXXX" << ""; + QTest::newRow("constructor with XXXXX prefix and suffix") << "qt_XXXXX_XXXXXX_XXXXX" << "qt_XXXXX_" << "_XXXXX" << ""; + + QTest::newRow("set template, no suffix") << "" << "foo" << "" << "foo"; + QTest::newRow("set template, with lowercase XXXXXX") << "" << "qt_" << "xxxxxx" << "qt_XXXXXXxxxxxx"; + QTest::newRow("set template, with xxx") << "" << "qt_" << ".xxx" << "qt_XXXXXX.xxx"; + QTest::newRow("set template, with >6 X's") << "" << "qt_" << ".xxx" << "qt_XXXXXXXXXXXXXX.xxx"; + QTest::newRow("set template, with >6 X's, no suffix") << "" << "qt_" << "" << "qt_XXXXXXXXXXXXXX"; +} + +void tst_QTemporaryFile::fileTemplate() +{ + QFETCH(QString, constructorTemplate); + QFETCH(QString, prefix); + QFETCH(QString, suffix); + QFETCH(QString, fileTemplate); + + QTemporaryFile file(constructorTemplate); + if (!fileTemplate.isEmpty()) + file.setFileTemplate(fileTemplate); + + QCOMPARE(file.open(), true); + + if (prefix.length()) + QCOMPARE(file.fileName().left(prefix.length()), prefix); + + if (suffix.length()) + QCOMPARE(file.fileName().right(suffix.length()), suffix); +} + + +/* + This tests whether the temporary file really gets placed in QDir::tempPath +*/ +void tst_QTemporaryFile::fileName() +{ + // Get QDir::tempPath and make an absolute path. + QString tempPath = QDir::tempPath(); + QString absoluteTempPath = QDir(tempPath).absolutePath(); + QTemporaryFile file; + file.setAutoRemove(true); + file.open(); + QString fileName = file.fileName(); + QVERIFY(QFile::exists(fileName)); + // Get path to the temp file, whithout the file name. + QString absoluteFilePath = QFileInfo(fileName).absolutePath(); +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + absoluteFilePath = absoluteFilePath.toLower(); + absoluteTempPath = absoluteTempPath.toLower(); +#endif + QCOMPARE(absoluteFilePath, absoluteTempPath); +} + +void tst_QTemporaryFile::fileNameIsEmpty() +{ + QString filename; + { + QTemporaryFile file; + QVERIFY(file.fileName().isEmpty()); + + QVERIFY(file.open()); + QVERIFY(!file.fileName().isEmpty()); + + filename = file.fileName(); + QVERIFY(QFile::exists(filename)); + + file.close(); + QVERIFY(!file.isOpen()); + QVERIFY(QFile::exists(filename)); + QVERIFY(!file.fileName().isEmpty()); + } + QVERIFY(!QFile::exists(filename)); +} + +void tst_QTemporaryFile::autoRemove() +{ + // Test auto remove + QString fileName; + { + QTemporaryFile file("tempXXXXXX"); + file.setAutoRemove(true); + QVERIFY(file.open()); + fileName = file.fileName(); + file.close(); + } + QVERIFY(!QFile::exists(fileName)); + + // Test if disabling auto remove works. + { + QTemporaryFile file("tempXXXXXX"); + file.setAutoRemove(false); + QVERIFY(file.open()); + fileName = file.fileName(); + file.close(); + } + QVERIFY(QFile::exists(fileName)); + QVERIFY(QFile::remove(fileName)); + + + // Do not explicitly call setAutoRemove (tests if it really is the default as documented) + { + QTemporaryFile file("tempXXXXXX"); + QVERIFY(file.open()); + fileName = file.fileName(); + file.close(); + } + QVERIFY(!QFile::exists(fileName)); + +} + +void tst_QTemporaryFile::write() +{ + QByteArray data("OLE\nOLE\nOLE"); + QTemporaryFile file; + QVERIFY(file.open()); + QCOMPARE((int)file.write(data), data.size()); + file.reset(); + QFile compare(file.fileName()); + compare.open(QIODevice::ReadOnly); + QCOMPARE(compare.readAll() , data); + file.close(); +} + +void tst_QTemporaryFile::openCloseOpenClose() +{ + QString fileName; + { + // Create a temp file + QTemporaryFile file("tempXXXXXX"); + file.setAutoRemove(true); + QVERIFY(file.open()); + file.write("OLE"); + fileName = file.fileName(); + QVERIFY(QFile::exists(fileName)); + file.close(); + + // Check that it still exists after being closed + QVERIFY(QFile::exists(fileName)); + QVERIFY(!file.isOpen()); + QVERIFY(file.open()); + QCOMPARE(file.readAll(), QByteArray("OLE")); + // Check that it's still the same file after being opened again. + QCOMPARE(file.fileName(), fileName); + } + QVERIFY(!QFile::exists(fileName)); +} + +void tst_QTemporaryFile::size() +{ + QTemporaryFile file; + QVERIFY(file.open()); + QVERIFY(file.exists()); + QVERIFY(!file.isSequential()); + QByteArray str("foobar"); + file.write(str); + QVERIFY(QFile::exists(file.fileName())); + // On CE it takes more time for the filesystem to update + // the information. Usually you have to close it or seek + // to get latest information. flush() does not help either. +#if !defined(Q_OS_WINCE) + QCOMPARE(file.size(), qint64(6)); +#endif + file.seek(0); + QCOMPARE(file.size(), qint64(6)); +} + +void tst_QTemporaryFile::resize() +{ + QTemporaryFile file; + file.setAutoRemove(true); + QVERIFY(file.open()); + QVERIFY(file.resize(100)); + + QCOMPARE(QFileInfo(file.fileName()).size(), qint64(100)); + + file.close(); +} + +void tst_QTemporaryFile::openOnRootDrives() +{ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + unsigned int lastErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); +#endif + // If it's possible to create a file in the root directory, it + // must be possible to create a temp file there too. + foreach (QFileInfo driveInfo, QDir::drives()) { + QFile testFile(driveInfo.filePath() + "XXXXXX.txt"); + if (testFile.open(QIODevice::ReadWrite)) { + testFile.remove(); + QTemporaryFile file(driveInfo.filePath() + "XXXXXX.txt"); + file.setAutoRemove(true); + QVERIFY(file.open()); + } + } +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + SetErrorMode(lastErrorMode); +#endif +} + +void tst_QTemporaryFile::stressTest() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + // 200 is still ok, first colision happens after ~30 + const int iterations = 200; +#else + const int iterations = 1000; +#endif + + QSet<QString> names; + for (int i = 0; i < iterations; ++i) { + QTemporaryFile file; + file.setAutoRemove(false); + QVERIFY2(file.open(), qPrintable(file.errorString())); + QVERIFY(!names.contains(file.fileName())); + names.insert(file.fileName()); + } + for (QSet<QString>::const_iterator it = names.constBegin(); it != names.constEnd(); ++it) { + QFile::remove(*it); + } +} + +void tst_QTemporaryFile::rename() +{ + // This test checks that the temporary file is deleted, even after a + // rename. + + QDir dir; + QVERIFY(!dir.exists("temporary-file.txt")); + + QString tempname; + { + QTemporaryFile file(dir.filePath("temporary-file.XXXXXX")); + + QVERIFY(file.open()); + tempname = file.fileName(); + QVERIFY(dir.exists(tempname)); + + QVERIFY(file.rename("temporary-file.txt")); + QVERIFY(!dir.exists(tempname)); + QVERIFY(dir.exists("temporary-file.txt")); + QCOMPARE(file.fileName(), QString("temporary-file.txt")); + } + + QVERIFY(!dir.exists(tempname)); + QVERIFY(!dir.exists("temporary-file.txt")); +} + +void tst_QTemporaryFile::renameFdLeak() +{ +#ifdef Q_OS_UNIX + // Test this on Unix only + + // Open a bunch of files to force the fd count to go up + static const int count = 10; + int bunch_of_files[count]; + for (int i = 0; i < count; ++i) { + bunch_of_files[i] = ::open(SRCDIR "tst_qtemporaryfile.cpp", O_RDONLY); + QVERIFY(bunch_of_files[i] != -1); + } + + int fd; + { + QTemporaryFile file; + file.setAutoRemove(false); + QVERIFY(file.open()); + + // close the bunch of files + for (int i = 0; i < count; ++i) + ::close(bunch_of_files[i]); + + // save the file descriptor for later + fd = file.handle(); + + // rename the file to something + QString newPath = QDir::tempPath() + "/tst_qtemporaryfile-renameFdLeak-" + QString::number(getpid()); + file.rename(newPath); + QFile::remove(newPath); + } + + // check if QTemporaryFile closed the file + QVERIFY(::close(fd) == -1 && errno == EBADF); +#endif +} + +void tst_QTemporaryFile::reOpenThroughQFile() +{ + QByteArray data("abcdefghij"); + + QTemporaryFile file; + QVERIFY(((QFile &)file).open(QIODevice::WriteOnly)); + QCOMPARE(file.write(data), (qint64)data.size()); + + file.close(); + QVERIFY(file.open()); + QCOMPARE(file.readAll(), data); +} + +void tst_QTemporaryFile::keepOpenMode() +{ + QByteArray data("abcdefghij"); + + { + QTemporaryFile file; + QVERIFY(((QFile &)file).open(QIODevice::WriteOnly)); + QVERIFY(QIODevice::WriteOnly == file.openMode()); + + QCOMPARE(file.write(data), (qint64)data.size()); + file.close(); + + QVERIFY(((QFile &)file).open(QIODevice::ReadOnly)); + QVERIFY(QIODevice::ReadOnly == file.openMode()); + QCOMPARE(file.readAll(), data); + } + + { + QTemporaryFile file; + QVERIFY(file.open()); + QCOMPARE(file.write(data), (qint64)data.size()); + QVERIFY(file.rename("temporary-file.txt")); + + QVERIFY(((QFile &)file).open(QIODevice::ReadOnly)); + QVERIFY(QIODevice::ReadOnly == file.openMode()); + QCOMPARE(file.readAll(), data); + + QVERIFY(((QFile &)file).open(QIODevice::WriteOnly)); + QVERIFY(QIODevice::WriteOnly == file.openMode()); + } +} + +void tst_QTemporaryFile::resetTemplateAfterError() +{ + // calling setFileTemplate on a failed open + + QString tempPath = QDir::tempPath(); + + QString const fileTemplate("destination/qt_temp_file_test.XXXXXX"); + QString const fileTemplate2(tempPath + "/qt_temp_file_test.XXXXXX"); + + QVERIFY2( QDir(tempPath).exists() || QDir().mkpath(tempPath), "Test precondition" ); + QVERIFY2( !QFile::exists("destination"), "Test precondition" ); + QVERIFY2( !QFile::exists(fileTemplate2) || QFile::remove(fileTemplate2), "Test precondition" ); + + QFile file(fileTemplate2); + QByteArray fileContent("This file is intentionally NOT left empty."); + + QVERIFY( file.open(QIODevice::ReadWrite | QIODevice::Truncate) ); + QCOMPARE( file.write(fileContent), (qint64)fileContent.size() ); + QVERIFY( file.flush() ); + + QString fileName; + { + QTemporaryFile temp; + + QVERIFY( temp.fileName().isEmpty() ); + QVERIFY( !temp.fileTemplate().isEmpty() ); + + temp.setFileTemplate( fileTemplate ); + + QVERIFY( temp.fileName().isEmpty() ); + QCOMPARE( temp.fileTemplate(), fileTemplate ); + + QVERIFY( !temp.open() ); + + QVERIFY( temp.fileName().isEmpty() ); + QCOMPARE( temp.fileTemplate(), fileTemplate ); + + temp.setFileTemplate( fileTemplate2 ); + QVERIFY( temp.open() ); + + fileName = temp.fileName(); + QVERIFY( QFile::exists(fileName) ); + QVERIFY( !fileName.isEmpty() ); + QVERIFY2( fileName != fileTemplate2, + ("Generated name shouldn't be same as template: " + fileTemplate2).toLocal8Bit().constData() ); + } + + QVERIFY( !QFile::exists(fileName) ); + + file.seek(0); + QCOMPARE( QString(file.readAll()), QString(fileContent) ); + QVERIFY( file.remove() ); +} + +void tst_QTemporaryFile::setTemplateAfterOpen() +{ + QTemporaryFile temp; + + QVERIFY( temp.fileName().isEmpty() ); + QVERIFY( !temp.fileTemplate().isEmpty() ); + + QVERIFY( temp.open() ); + + QString const fileName = temp.fileName(); + QString const newTemplate("funny-path/funny-name-XXXXXX.tmp"); + + QVERIFY( !fileName.isEmpty() ); + QVERIFY( QFile::exists(fileName) ); + QVERIFY( !temp.fileTemplate().isEmpty() ); + QVERIFY( temp.fileTemplate() != newTemplate ); + + temp.close(); // QTemporaryFile::setFileTemplate will assert on isOpen() up to 4.5.2 + temp.setFileTemplate(newTemplate); + QCOMPARE( temp.fileTemplate(), newTemplate ); + + QVERIFY( temp.open() ); + QCOMPARE( temp.fileName(), fileName ); + QCOMPARE( temp.fileTemplate(), newTemplate ); +} + +void tst_QTemporaryFile::autoRemoveAfterFailedRename() +{ + struct CleanOnReturn + { + ~CleanOnReturn() + { + if (!tempName.isEmpty()) + QFile::remove(tempName); + } + + void reset() + { + tempName.clear(); + } + + QString tempName; + }; + + CleanOnReturn cleaner; + + { + QTemporaryFile file; + QVERIFY( file.open() ); + cleaner.tempName = file.fileName(); + + QVERIFY( QFile::exists(cleaner.tempName) ); + QVERIFY( !QFileInfo("i-do-not-exist").isDir() ); + QVERIFY( !file.rename("i-do-not-exist/file.txt") ); + QVERIFY( QFile::exists(cleaner.tempName) ); + } + + QVERIFY( !QFile::exists(cleaner.tempName) ); + cleaner.reset(); +} + +void tst_QTemporaryFile::QTBUG_4796_data() +{ + QTest::addColumn<QString>("prefix"); + QTest::addColumn<QString>("suffix"); + QTest::addColumn<bool>("openResult"); + + QString unicode = QString::fromUtf8("\xc3\xa5\xc3\xa6\xc3\xb8"); + + QTest::newRow("<empty>") << QString() << QString() << true; + QTest::newRow("blaXXXXXX") << QString("bla") << QString() << true; + QTest::newRow("XXXXXXbla") << QString() << QString("bla") << true; + QTest::newRow("does-not-exist/qt_temp.XXXXXX") << QString("does-not-exist/qt_temp") << QString() << false; + QTest::newRow("XXXXXX<unicode>") << QString() << unicode << true; + QTest::newRow("<unicode>XXXXXX") << unicode << QString() << true; + QTest::newRow("<unicode>XXXXXX<unicode>") << unicode << unicode << true; +} + +void tst_QTemporaryFile::QTBUG_4796() +{ + QVERIFY(QDir("test-XXXXXX").exists()); + + struct CleanOnReturn + { + ~CleanOnReturn() + { + Q_FOREACH(QString tempName, tempNames) + QFile::remove(tempName); + } + + void reset() + { + tempNames.clear(); + } + + QStringList tempNames; + }; + + CleanOnReturn cleaner; + + QFETCH(QString, prefix); + QFETCH(QString, suffix); + QFETCH(bool, openResult); + + { + QString fileTemplate1 = prefix + QString("XX") + suffix; + QString fileTemplate2 = prefix + QString("XXXX") + suffix; + QString fileTemplate3 = prefix + QString("XXXXXX") + suffix; + QString fileTemplate4 = prefix + QString("XXXXXXXX") + suffix; + + QTemporaryFile file1(fileTemplate1); + QTemporaryFile file2(fileTemplate2); + QTemporaryFile file3(fileTemplate3); + QTemporaryFile file4(fileTemplate4); + QTemporaryFile file5("test-XXXXXX/" + fileTemplate1); + QTemporaryFile file6("test-XXXXXX/" + fileTemplate3); + + QCOMPARE(file1.open(), openResult); + QCOMPARE(file2.open(), openResult); + QCOMPARE(file3.open(), openResult); + QCOMPARE(file4.open(), openResult); + QCOMPARE(file5.open(), openResult); + QCOMPARE(file6.open(), openResult); + + QCOMPARE(file1.exists(), openResult); + QCOMPARE(file2.exists(), openResult); + QCOMPARE(file3.exists(), openResult); + QCOMPARE(file4.exists(), openResult); + QCOMPARE(file5.exists(), openResult); + QCOMPARE(file6.exists(), openResult); + + // make sure the file exists under the *correct* name + if (openResult) { + cleaner.tempNames << file1.fileName() + << file2.fileName() + << file3.fileName() + << file4.fileName() + << file5.fileName() + << file6.fileName(); + + QVERIFY(file1.fileName().startsWith(fileTemplate1 + QLatin1Char('.'))); + QVERIFY(file2.fileName().startsWith(fileTemplate2 + QLatin1Char('.'))); + QVERIFY(file5.fileName().startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.'))); + QVERIFY(file6.fileName().startsWith("test-XXXXXX/" + prefix)); + + if (!prefix.isEmpty()) { + QVERIFY(file3.fileName().startsWith(prefix)); + QVERIFY(file4.fileName().startsWith(prefix)); + } + + if (!suffix.isEmpty()) { + QVERIFY(file3.fileName().endsWith(suffix)); + QVERIFY(file4.fileName().endsWith(suffix)); + QVERIFY(file6.fileName().endsWith(suffix)); + } + } + } + + Q_FOREACH(QString const &tempName, cleaner.tempNames) + QVERIFY( !QFile::exists(tempName) ); + + cleaner.reset(); +} + +QTEST_MAIN(tst_QTemporaryFile) +#include "tst_qtemporaryfile.moc" diff --git a/tests/auto/corelib/io/qtextstream/.gitattributes b/tests/auto/corelib/io/qtextstream/.gitattributes new file mode 100644 index 0000000000..eb78a3cecf --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/.gitattributes @@ -0,0 +1,3 @@ +rfc3261.txt -crlf +task113817.txt -crlf +shift-jis.txt -crlf diff --git a/tests/auto/corelib/io/qtextstream/.gitignore b/tests/auto/corelib/io/qtextstream/.gitignore new file mode 100644 index 0000000000..01f26ae749 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/.gitignore @@ -0,0 +1,11 @@ +bom.txt +out.txt +readAllStdinProcess/readAllStdinProcess +readAllStdinProcess/readAllStdinProcess.exe +readLineStdinProcess/readLineStdinProcess +readLineStdinProcess/readLineStdinProcess.exe +stdinProcess/stdinProcess +stdinProcess/stdinProcess.exe +testfile +tst_qtextstream +utf8bom diff --git a/tests/auto/corelib/io/qtextstream/qtextstream.pro b/tests/auto/corelib/io/qtextstream/qtextstream.pro new file mode 100644 index 0000000000..a2dcc8108d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/qtextstream.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs +SUBDIRS = test +!symbian: SUBDIRS += stdinProcess readAllStdinProcess readLineStdinProcess + + + diff --git a/tests/auto/corelib/io/qtextstream/qtextstream.qrc b/tests/auto/corelib/io/qtextstream/qtextstream.qrc new file mode 100644 index 0000000000..a750e35d4a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/qtextstream.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/tst_textstream/"> + <file>resources/big_endian/</file> + <file>resources/little_endian/</file> +</qresource> +</RCC> diff --git a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp new file mode 100644 index 0000000000..ca541d053a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore> + +int main(int argc, char **argv) +{ + QCoreApplication a(argc, argv); + qDebug() << QTextStream(stdin).readAll(); + return 0; +} diff --git a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/readAllStdinProcess.pro b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/readAllStdinProcess.pro new file mode 100644 index 0000000000..9cf4d19387 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/readAllStdinProcess.pro @@ -0,0 +1,7 @@ +SOURCES += main.cpp +QT = core +CONFIG += console +CONFIG -= app_bundle +DESTDIR = ./ + + diff --git a/tests/auto/corelib/io/qtextstream/readLineStdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/readLineStdinProcess/main.cpp new file mode 100644 index 0000000000..d8d2eed000 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/readLineStdinProcess/main.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore> + +int main(int argc, char **argv) +{ + QCoreApplication a(argc, argv); + QTextStream qin(stdin); + QTextStream qerr(stderr); + QString line; + do { + line = qin.readLine(); + if (!line.isNull()) + qerr << line << flush; + } while (!line.isNull()); + return 0; +} diff --git a/tests/auto/corelib/io/qtextstream/readLineStdinProcess/readLineStdinProcess.pro b/tests/auto/corelib/io/qtextstream/readLineStdinProcess/readLineStdinProcess.pro new file mode 100644 index 0000000000..9cf4d19387 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/readLineStdinProcess/readLineStdinProcess.pro @@ -0,0 +1,7 @@ +SOURCES += main.cpp +QT = core +CONFIG += console +CONFIG -= app_bundle +DESTDIR = ./ + + diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Latin1_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Locale_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..849ecb39ed --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..8b9647f06f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..d73722e724 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_0.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_0.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_1.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_1.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..fcb209d377 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..7939963f78 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..d155ca2863 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_0.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_0.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_1.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_1.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..104e45f940 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..3135276780 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..993d0b9e19 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_0.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_0.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_1.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_1.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..fcb209d377 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..7939963f78 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..d155ca2863 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QByteArray_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_3.data new file mode 100644 index 0000000000..fa7af8bf5f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_3.data @@ -0,0 +1 @@ +z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_4.data new file mode 100644 index 0000000000..b516b2c489 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Latin1_4.data @@ -0,0 +1 @@ +@
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_3.data new file mode 100644 index 0000000000..fa7af8bf5f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_3.data @@ -0,0 +1 @@ +z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_4.data new file mode 100644 index 0000000000..b516b2c489 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Locale_4.data @@ -0,0 +1 @@ +@
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..6def16c99e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..57302ad8e7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..239c14d498 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..8fbd3327c8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..d745e1be7b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..db52135603 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..0a4ca93c16 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e7c7d5a76b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..7501b59181 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..1565aaa95f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..9ac3ad9a6b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..bb28df16b9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..8c0f57437b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d494004e64 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..de421979ea --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..fa7af8bf5f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ +z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..b516b2c489 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +@
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..db52135603 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..0a4ca93c16 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..e7c7d5a76b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..7501b59181 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..1565aaa95f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QChar_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Latin1_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Locale_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..849ecb39ed --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..8b9647f06f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..d73722e724 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_0.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_0.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_1.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_1.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..fcb209d377 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..7939963f78 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..d155ca2863 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..104e45f940 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..3135276780 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..993d0b9e19 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_0.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_0.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_1.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_1.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..fcb209d377 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..7939963f78 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..d155ca2863 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_QString_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_3.data new file mode 100644 index 0000000000..9280c0d31d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_3.data @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_4.data new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Latin1_4.data @@ -0,0 +1 @@ +0
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_3.data new file mode 100644 index 0000000000..9280c0d31d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_3.data @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_4.data new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Locale_4.data @@ -0,0 +1 @@ +0
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..6def16c99e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..57302ad8e7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..239c14d498 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..819b31d1f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..a6ff072af1 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..db52135603 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..0a4ca93c16 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e7c7d5a76b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..bf9cec8ea7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..ec4665f7ff --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..9ac3ad9a6b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..bb28df16b9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..8c0f57437b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..878dc8a26e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..fd0779e0f3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..9280c0d31d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +0
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..db52135603 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..0a4ca93c16 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..e7c7d5a76b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..bf9cec8ea7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..ec4665f7ff --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_char_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_5.data new file mode 100644 index 0000000000..80aed3622e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_5.data @@ -0,0 +1 @@ + A 1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_6.data new file mode 100644 index 0000000000..aec027753d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Latin1_6.data @@ -0,0 +1 @@ + A -1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_5.data new file mode 100644 index 0000000000..80aed3622e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_5.data @@ -0,0 +1 @@ + A 1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_6.data new file mode 100644 index 0000000000..aec027753d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Locale_6.data @@ -0,0 +1 @@ + A -1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..67ce8d83c8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..9662a9aaa1 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..a74511b101 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..bdc06a6ec2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_5.data Binary files differnew file mode 100644 index 0000000000..79b15d4d8a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_6.data Binary files differnew file mode 100644 index 0000000000..2141e65843 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_RawUnicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..61cc689e1e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..cf914bc67e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..5e08ff706a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..b6f4541bb8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_5.data Binary files differnew file mode 100644 index 0000000000..f4a50d829a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_6.data Binary files differnew file mode 100644 index 0000000000..2d8f67152c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeNetworkOrder_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..e6b94bbeb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..fb0a550264 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..48fe53930f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..811e93212d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_5.data Binary files differnew file mode 100644 index 0000000000..7041fa9b4d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_6.data Binary files differnew file mode 100644 index 0000000000..9fd21fade0 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeReverse_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_5.data new file mode 100644 index 0000000000..80aed3622e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_5.data @@ -0,0 +1 @@ + A 1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_6.data new file mode 100644 index 0000000000..aec027753d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_UnicodeUTF8_6.data @@ -0,0 +1 @@ + A -1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..61cc689e1e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..cf914bc67e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..5e08ff706a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..b6f4541bb8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_5.data Binary files differnew file mode 100644 index 0000000000..f4a50d829a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_6.data Binary files differnew file mode 100644 index 0000000000..2d8f67152c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_double_resource_Unicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Latin1_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Locale_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..67ce8d83c8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..9662a9aaa1 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..a74511b101 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..bdc06a6ec2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..61cc689e1e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..cf914bc67e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..5e08ff706a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..b6f4541bb8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..e6b94bbeb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..fb0a550264 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..48fe53930f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..811e93212d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..61cc689e1e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..cf914bc67e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..5e08ff706a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..b6f4541bb8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_float_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_8.data new file mode 100644 index 0000000000..f4aefab396 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Latin1_8.data @@ -0,0 +1 @@ + A -512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_8.data new file mode 100644 index 0000000000..f4aefab396 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Locale_8.data @@ -0,0 +1 @@ + A -512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..815d4fc7db --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..c933a04c07 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..69de5ef2bd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..c45139955a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_5.data Binary files differnew file mode 100644 index 0000000000..396352f4d6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_6.data Binary files differnew file mode 100644 index 0000000000..ea73fac731 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_7.data Binary files differnew file mode 100644 index 0000000000..1f4f1a58de --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_8.data Binary files differnew file mode 100644 index 0000000000..9469ca407f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_RawUnicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_5.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_6.data Binary files differnew file mode 100644 index 0000000000..18c3344c26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_7.data Binary files differnew file mode 100644 index 0000000000..5193701ae3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_8.data Binary files differnew file mode 100644 index 0000000000..fab38d24ef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeNetworkOrder_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_5.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_6.data Binary files differnew file mode 100644 index 0000000000..ebb14b2fbd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_7.data Binary files differnew file mode 100644 index 0000000000..a9e1432ca9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_8.data Binary files differnew file mode 100644 index 0000000000..b7e6743c28 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeReverse_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_8.data new file mode 100644 index 0000000000..f4aefab396 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_UnicodeUTF8_8.data @@ -0,0 +1 @@ + A -512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_5.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_6.data Binary files differnew file mode 100644 index 0000000000..18c3344c26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_7.data Binary files differnew file mode 100644 index 0000000000..5193701ae3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_8.data Binary files differnew file mode 100644 index 0000000000..fab38d24ef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_int_resource_Unicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_8.data new file mode 100644 index 0000000000..cab2ee4938 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Latin1_8.data @@ -0,0 +1 @@ + A -65534 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_8.data new file mode 100644 index 0000000000..cab2ee4938 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Locale_8.data @@ -0,0 +1 @@ + A -65534 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..815d4fc7db --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..c933a04c07 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..69de5ef2bd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..40269f4e0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_5.data Binary files differnew file mode 100644 index 0000000000..396352f4d6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_6.data Binary files differnew file mode 100644 index 0000000000..ea73fac731 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_7.data Binary files differnew file mode 100644 index 0000000000..1f4f1a58de --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_8.data Binary files differnew file mode 100644 index 0000000000..e8051f8906 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_RawUnicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..e50e2d02a9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_5.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_6.data Binary files differnew file mode 100644 index 0000000000..18c3344c26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_7.data Binary files differnew file mode 100644 index 0000000000..5193701ae3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_8.data Binary files differnew file mode 100644 index 0000000000..5a9cb07f57 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeNetworkOrder_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..e20c76a82c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_5.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_6.data Binary files differnew file mode 100644 index 0000000000..ebb14b2fbd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_7.data Binary files differnew file mode 100644 index 0000000000..a9e1432ca9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_8.data Binary files differnew file mode 100644 index 0000000000..f8ec5bc443 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeReverse_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_8.data new file mode 100644 index 0000000000..cab2ee4938 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_UnicodeUTF8_8.data @@ -0,0 +1 @@ + A -65534 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..e50e2d02a9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_5.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_6.data Binary files differnew file mode 100644 index 0000000000..18c3344c26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_7.data Binary files differnew file mode 100644 index 0000000000..5193701ae3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_8.data Binary files differnew file mode 100644 index 0000000000..5a9cb07f57 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_long_resource_Unicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_1.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_1.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_2.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_2.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_4.data new file mode 100644 index 0000000000..02b7f3ab7b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Latin1_4.data @@ -0,0 +1 @@ + A -254 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_1.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_1.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_2.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_2.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_4.data new file mode 100644 index 0000000000..02b7f3ab7b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Locale_4.data @@ -0,0 +1 @@ + A -254 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..396352f4d6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..815d4fc7db --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..69de5ef2bd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..0dc83d2713 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..b951b56531 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..80d3ca2ef1 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..02b7f3ab7b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A -254 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..b951b56531 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_short_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Latin1_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Locale_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..815d4fc7db --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..c933a04c07 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..69de5ef2bd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..c45139955a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_uint_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Latin1_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Locale_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..815d4fc7db --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..c933a04c07 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..69de5ef2bd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..40269f4e0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..e50e2d02a9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..e20c76a82c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..e50e2d02a9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ulong_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Latin1_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Locale_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..feac21f921 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..815d4fc7db --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..c933a04c07 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..69de5ef2bd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..c45139955a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shift_ushort_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource0.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource0.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource0.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource1.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource1.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource1.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource10.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource10.data new file mode 100644 index 0000000000..597f94465c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource10.data @@ -0,0 +1 @@ +I-am-a-string
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource11.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource11.data new file mode 100644 index 0000000000..597f94465c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource11.data @@ -0,0 +1 @@ +I-am-a-string
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource12.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource12.data new file mode 100644 index 0000000000..597f94465c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource12.data @@ -0,0 +1 @@ +I-am-a-string
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource2.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource2.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource2.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource20.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource20.data new file mode 100644 index 0000000000..b9e3a5a7c7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource20.data @@ -0,0 +1 @@ +ïŸ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource21.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource21.data new file mode 100644 index 0000000000..7014dc882f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource21.data @@ -0,0 +1 @@ +賿
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource3.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource3.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource3.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource4.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource4.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource4.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource5.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource5.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource5.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource6.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource6.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource6.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource7.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource7.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource7.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource8.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource8.data new file mode 100644 index 0000000000..4f3af7006e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource8.data @@ -0,0 +1 @@ +3.1415
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource9.data b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource9.data new file mode 100644 index 0000000000..4f3af7006e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/big_endian/operator_shiftright_resource9.data @@ -0,0 +1 @@ +3.1415
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Latin1_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Locale_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..4d5bdc553e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..3cf181c23c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..f7f74e56a0 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_0.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_0.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_1.data new file mode 100644 index 0000000000..e2df5e2ee7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_1.data @@ -0,0 +1 @@ +þÿ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..fcb209d377 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..7939963f78 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..d155ca2863 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_0.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_0.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_1.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_1.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..104e45f940 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..3135276780 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..993d0b9e19 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_0.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_0.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_1.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_1.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..104e45f940 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..3135276780 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..993d0b9e19 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QByteArray_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_3.data new file mode 100644 index 0000000000..fa7af8bf5f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_3.data @@ -0,0 +1 @@ +z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_4.data new file mode 100644 index 0000000000..b516b2c489 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Latin1_4.data @@ -0,0 +1 @@ +@
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_3.data new file mode 100644 index 0000000000..fa7af8bf5f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_3.data @@ -0,0 +1 @@ +z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_4.data new file mode 100644 index 0000000000..b516b2c489 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Locale_4.data @@ -0,0 +1 @@ +@
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..e2b43e3781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..962fc922ad --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..839cc09ec8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..f71ac66a63 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..88f99805e3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..db52135603 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..0a4ca93c16 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e7c7d5a76b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..7501b59181 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..1565aaa95f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..9ac3ad9a6b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..bb28df16b9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..8c0f57437b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d494004e64 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..de421979ea --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..fa7af8bf5f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ +z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..b516b2c489 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +@
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..9ac3ad9a6b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..bb28df16b9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..8c0f57437b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..d494004e64 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..de421979ea --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QChar_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Latin1_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Locale_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..4d5bdc553e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..3cf181c23c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..f7f74e56a0 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..fcb209d377 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..7939963f78 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..d155ca2863 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_0.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_0.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_1.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_1.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..104e45f940 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..3135276780 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..993d0b9e19 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +foo
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..a907ec3f43 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_3.data @@ -0,0 +1,2 @@ +foo +bar
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..61cd46aacc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +cjacka ckha cka ckah ckac kahckadhcbkgdk vkzdfbvajef vkahv
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_0.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_0.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_1.data new file mode 100644 index 0000000000..46b134b197 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_1.data @@ -0,0 +1 @@ +ÿþ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..104e45f940 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..3135276780 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..993d0b9e19 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_QString_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_3.data new file mode 100644 index 0000000000..9280c0d31d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_3.data @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_4.data new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Latin1_4.data @@ -0,0 +1 @@ +0
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_3.data new file mode 100644 index 0000000000..9280c0d31d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_3.data @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_4.data new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Locale_4.data @@ -0,0 +1 @@ +0
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..e2b43e3781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..962fc922ad --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..839cc09ec8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..c33473a370 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..def7fcb589 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..db52135603 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..0a4ca93c16 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e7c7d5a76b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..bf9cec8ea7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..ec4665f7ff --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..9ac3ad9a6b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..bb28df16b9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..8c0f57437b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..878dc8a26e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..fd0779e0f3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..8c7e5a667f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ +A
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..7371f47a6f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ +B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..9280c0d31d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c227083464 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ +0
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..9ac3ad9a6b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..bb28df16b9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..8c0f57437b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..878dc8a26e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..fd0779e0f3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_char_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_5.data new file mode 100644 index 0000000000..80aed3622e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_5.data @@ -0,0 +1 @@ + A 1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_6.data new file mode 100644 index 0000000000..aec027753d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Latin1_6.data @@ -0,0 +1 @@ + A -1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_5.data new file mode 100644 index 0000000000..80aed3622e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_5.data @@ -0,0 +1 @@ + A 1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_6.data new file mode 100644 index 0000000000..aec027753d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Locale_6.data @@ -0,0 +1 @@ + A -1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..fb911f7352 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..efbc06bf26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..4d857caa13 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..b125e2084f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_5.data Binary files differnew file mode 100644 index 0000000000..f39fbde113 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_6.data Binary files differnew file mode 100644 index 0000000000..5436b427ed --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_RawUnicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..61cc689e1e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..cf914bc67e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..5e08ff706a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..b6f4541bb8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_5.data Binary files differnew file mode 100644 index 0000000000..f4a50d829a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_6.data Binary files differnew file mode 100644 index 0000000000..2d8f67152c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeNetworkOrder_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..e6b94bbeb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..fb0a550264 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..48fe53930f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..811e93212d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_5.data Binary files differnew file mode 100644 index 0000000000..7041fa9b4d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_6.data Binary files differnew file mode 100644 index 0000000000..9fd21fade0 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeReverse_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_5.data new file mode 100644 index 0000000000..80aed3622e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_5.data @@ -0,0 +1 @@ + A 1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_6.data new file mode 100644 index 0000000000..aec027753d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_UnicodeUTF8_6.data @@ -0,0 +1 @@ + A -1.23456789 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..e6b94bbeb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..fb0a550264 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..48fe53930f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..811e93212d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_5.data Binary files differnew file mode 100644 index 0000000000..7041fa9b4d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_6.data Binary files differnew file mode 100644 index 0000000000..9fd21fade0 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_double_resource_Unicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Latin1_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Locale_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..fb911f7352 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..efbc06bf26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..4d857caa13 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..b125e2084f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..61cc689e1e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..cf914bc67e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..5e08ff706a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..b6f4541bb8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..e6b94bbeb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..fb0a550264 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..48fe53930f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..811e93212d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..d2fa166d7d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..1d0fa9e6a6 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A -0.0001 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..e47d45c143 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..47ce07d283 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A -3.45678 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..e6b94bbeb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..fb0a550264 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..48fe53930f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..811e93212d --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_float_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_8.data new file mode 100644 index 0000000000..f4aefab396 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Latin1_8.data @@ -0,0 +1 @@ + A -512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_8.data new file mode 100644 index 0000000000..f4aefab396 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Locale_8.data @@ -0,0 +1 @@ + A -512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..ee113d1cf3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..1e07040ef4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..cc7ab7dff8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..450072bc4e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_5.data Binary files differnew file mode 100644 index 0000000000..73f5f259f8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_6.data Binary files differnew file mode 100644 index 0000000000..9805422dfb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_7.data Binary files differnew file mode 100644 index 0000000000..77f557a494 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_8.data Binary files differnew file mode 100644 index 0000000000..8dd6a4b38e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_RawUnicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_5.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_6.data Binary files differnew file mode 100644 index 0000000000..18c3344c26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_7.data Binary files differnew file mode 100644 index 0000000000..5193701ae3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_8.data Binary files differnew file mode 100644 index 0000000000..fab38d24ef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeNetworkOrder_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_5.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_6.data Binary files differnew file mode 100644 index 0000000000..ebb14b2fbd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_7.data Binary files differnew file mode 100644 index 0000000000..a9e1432ca9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_8.data Binary files differnew file mode 100644 index 0000000000..b7e6743c28 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeReverse_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_8.data new file mode 100644 index 0000000000..f4aefab396 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_UnicodeUTF8_8.data @@ -0,0 +1 @@ + A -512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_5.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_6.data Binary files differnew file mode 100644 index 0000000000..ebb14b2fbd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_7.data Binary files differnew file mode 100644 index 0000000000..a9e1432ca9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_8.data Binary files differnew file mode 100644 index 0000000000..b7e6743c28 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_int_resource_Unicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_8.data new file mode 100644 index 0000000000..cab2ee4938 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Latin1_8.data @@ -0,0 +1 @@ + A -65534 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_8.data new file mode 100644 index 0000000000..cab2ee4938 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Locale_8.data @@ -0,0 +1 @@ + A -65534 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..ee113d1cf3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..1e07040ef4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..cc7ab7dff8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..beea1c3663 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_5.data Binary files differnew file mode 100644 index 0000000000..73f5f259f8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_6.data Binary files differnew file mode 100644 index 0000000000..9805422dfb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_7.data Binary files differnew file mode 100644 index 0000000000..77f557a494 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_8.data Binary files differnew file mode 100644 index 0000000000..be6f22a5ea --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_RawUnicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..e50e2d02a9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_5.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_6.data Binary files differnew file mode 100644 index 0000000000..18c3344c26 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_7.data Binary files differnew file mode 100644 index 0000000000..5193701ae3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_8.data Binary files differnew file mode 100644 index 0000000000..5a9cb07f57 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeNetworkOrder_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..e20c76a82c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_5.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_6.data Binary files differnew file mode 100644 index 0000000000..ebb14b2fbd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_7.data Binary files differnew file mode 100644 index 0000000000..a9e1432ca9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_8.data Binary files differnew file mode 100644 index 0000000000..f8ec5bc443 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeReverse_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_5.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_5.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_6.data new file mode 100644 index 0000000000..f171cb6c0c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_6.data @@ -0,0 +1 @@ + A -10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_7.data new file mode 100644 index 0000000000..de18d40ee8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_7.data @@ -0,0 +1 @@ + A -255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_8.data new file mode 100644 index 0000000000..cab2ee4938 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_UnicodeUTF8_8.data @@ -0,0 +1 @@ + A -65534 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..e20c76a82c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_5.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_5.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_6.data Binary files differnew file mode 100644 index 0000000000..ebb14b2fbd --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_6.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_7.data Binary files differnew file mode 100644 index 0000000000..a9e1432ca9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_7.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_8.data Binary files differnew file mode 100644 index 0000000000..f8ec5bc443 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_long_resource_Unicode_8.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_1.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_1.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_2.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_2.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_4.data new file mode 100644 index 0000000000..02b7f3ab7b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Latin1_4.data @@ -0,0 +1 @@ + A -254 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_1.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_1.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_2.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_2.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_4.data new file mode 100644 index 0000000000..02b7f3ab7b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Locale_4.data @@ -0,0 +1 @@ + A -254 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..73f5f259f8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..ee113d1cf3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..cc7ab7dff8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..584b17ea18 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..c52b277d9c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..b951b56531 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..80d3ca2ef1 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..ef70e7dc3a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A -1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..02b7f3ab7b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A -254 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..95742ec8f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..80d3ca2ef1 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_short_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Latin1_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Locale_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..ee113d1cf3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..1e07040ef4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..cc7ab7dff8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..450072bc4e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_uint_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Latin1_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Locale_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..ee113d1cf3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..1e07040ef4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..cc7ab7dff8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..beea1c3663 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..e50e2d02a9 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..e20c76a82c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..f667f77c45 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 65535 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..e20c76a82c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ulong_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Latin1_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Locale_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_0.data Binary files differnew file mode 100644 index 0000000000..775ae0f25b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_1.data Binary files differnew file mode 100644 index 0000000000..ee113d1cf3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_2.data Binary files differnew file mode 100644 index 0000000000..1e07040ef4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_3.data Binary files differnew file mode 100644 index 0000000000..cc7ab7dff8 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_4.data Binary files differnew file mode 100644 index 0000000000..450072bc4e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_RawUnicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_0.data Binary files differnew file mode 100644 index 0000000000..2262f5ecdb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_1.data Binary files differnew file mode 100644 index 0000000000..d7a098948e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_2.data Binary files differnew file mode 100644 index 0000000000..e333a695b7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_3.data Binary files differnew file mode 100644 index 0000000000..18bb47b042 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_4.data Binary files differnew file mode 100644 index 0000000000..9a9a22daef --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeNetworkOrder_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeReverse_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_0.data new file mode 100644 index 0000000000..35282318cb --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_0.data @@ -0,0 +1 @@ + A 0 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_1.data new file mode 100644 index 0000000000..30c3a50213 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_1.data @@ -0,0 +1 @@ + A 1 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_2.data new file mode 100644 index 0000000000..9d64c07ef2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_2.data @@ -0,0 +1 @@ + A 10 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_3.data new file mode 100644 index 0000000000..6b37eb602b --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_3.data @@ -0,0 +1 @@ + A 255 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_4.data new file mode 100644 index 0000000000..c0e22423bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_UnicodeUTF8_4.data @@ -0,0 +1 @@ + A 512 B
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_0.data Binary files differnew file mode 100644 index 0000000000..379e87b914 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_0.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_1.data Binary files differnew file mode 100644 index 0000000000..2785156fb3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_1.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_2.data Binary files differnew file mode 100644 index 0000000000..6dc818abc3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_2.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_3.data Binary files differnew file mode 100644 index 0000000000..d41a1f75d3 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_3.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_4.data Binary files differnew file mode 100644 index 0000000000..f5a0d874d4 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shift_ushort_resource_Unicode_4.data diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource0.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource0.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource0.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource1.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource1.data new file mode 100644 index 0000000000..0f13712411 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource1.data @@ -0,0 +1 @@ +Z
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource10.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource10.data new file mode 100644 index 0000000000..597f94465c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource10.data @@ -0,0 +1 @@ +I-am-a-string
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource11.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource11.data new file mode 100644 index 0000000000..597f94465c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource11.data @@ -0,0 +1 @@ +I-am-a-string
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource12.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource12.data new file mode 100644 index 0000000000..597f94465c --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource12.data @@ -0,0 +1 @@ +I-am-a-string
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource2.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource2.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource2.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource20.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource20.data new file mode 100644 index 0000000000..b9e3a5a7c7 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource20.data @@ -0,0 +1 @@ +ïŸ
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource21.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource21.data new file mode 100644 index 0000000000..7014dc882f --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource21.data @@ -0,0 +1 @@ +賿
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource3.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource3.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource3.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource4.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource4.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource4.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource5.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource5.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource5.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource6.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource6.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource6.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource7.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource7.data new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource7.data @@ -0,0 +1 @@ +12345
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource8.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource8.data new file mode 100644 index 0000000000..4f3af7006e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource8.data @@ -0,0 +1 @@ +3.1415
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource9.data b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource9.data new file mode 100644 index 0000000000..4f3af7006e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/resources/little_endian/operator_shiftright_resource9.data @@ -0,0 +1 @@ +3.1415
\ No newline at end of file diff --git a/tests/auto/corelib/io/qtextstream/rfc3261.txt b/tests/auto/corelib/io/qtextstream/rfc3261.txt new file mode 100644 index 0000000000..4cf4df93bc --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/rfc3261.txt @@ -0,0 +1,15067 @@ +
+
+
+
+
+
+Network Working Group J. Rosenberg
+Request for Comments: 3261 dynamicsoft
+Obsoletes: 2543 H. Schulzrinne
+Category: Standards Track Columbia U.
+ G. Camarillo
+ Ericsson
+ A. Johnston
+ WorldCom
+ J. Peterson
+ Neustar
+ R. Sparks
+ dynamicsoft
+ M. Handley
+ ICIR
+ E. Schooler
+ AT&T
+ June 2002
+
+ SIP: Session Initiation Protocol
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document describes Session Initiation Protocol (SIP), an
+ application-layer control (signaling) protocol for creating,
+ modifying, and terminating sessions with one or more participants.
+ These sessions include Internet telephone calls, multimedia
+ distribution, and multimedia conferences.
+
+ SIP invitations used to create sessions carry session descriptions
+ that allow participants to agree on a set of compatible media types.
+ SIP makes use of elements called proxy servers to help route requests
+ to the user's current location, authenticate and authorize users for
+ services, implement provider call-routing policies, and provide
+ features to users. SIP also provides a registration function that
+ allows users to upload their current locations for use by proxy
+ servers. SIP runs on top of several different transport protocols.
+
+
+
+Rosenberg, et. al. Standards Track [Page 1]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Table of Contents
+
+ 1 Introduction ........................................ 8
+ 2 Overview of SIP Functionality ....................... 9
+ 3 Terminology ......................................... 10
+ 4 Overview of Operation ............................... 10
+ 5 Structure of the Protocol ........................... 18
+ 6 Definitions ......................................... 20
+ 7 SIP Messages ........................................ 26
+ 7.1 Requests ............................................ 27
+ 7.2 Responses ........................................... 28
+ 7.3 Header Fields ....................................... 29
+ 7.3.1 Header Field Format ................................. 30
+ 7.3.2 Header Field Classification ......................... 32
+ 7.3.3 Compact Form ........................................ 32
+ 7.4 Bodies .............................................. 33
+ 7.4.1 Message Body Type ................................... 33
+ 7.4.2 Message Body Length ................................. 33
+ 7.5 Framing SIP Messages ................................ 34
+ 8 General User Agent Behavior ......................... 34
+ 8.1 UAC Behavior ........................................ 35
+ 8.1.1 Generating the Request .............................. 35
+ 8.1.1.1 Request-URI ......................................... 35
+ 8.1.1.2 To .................................................. 36
+ 8.1.1.3 From ................................................ 37
+ 8.1.1.4 Call-ID ............................................. 37
+ 8.1.1.5 CSeq ................................................ 38
+ 8.1.1.6 Max-Forwards ........................................ 38
+ 8.1.1.7 Via ................................................. 39
+ 8.1.1.8 Contact ............................................. 40
+ 8.1.1.9 Supported and Require ............................... 40
+ 8.1.1.10 Additional Message Components ....................... 41
+ 8.1.2 Sending the Request ................................. 41
+ 8.1.3 Processing Responses ................................ 42
+ 8.1.3.1 Transaction Layer Errors ............................ 42
+ 8.1.3.2 Unrecognized Responses .............................. 42
+ 8.1.3.3 Vias ................................................ 43
+ 8.1.3.4 Processing 3xx Responses ............................ 43
+ 8.1.3.5 Processing 4xx Responses ............................ 45
+ 8.2 UAS Behavior ........................................ 46
+ 8.2.1 Method Inspection ................................... 46
+ 8.2.2 Header Inspection ................................... 46
+ 8.2.2.1 To and Request-URI .................................. 46
+ 8.2.2.2 Merged Requests ..................................... 47
+ 8.2.2.3 Require ............................................. 47
+ 8.2.3 Content Processing .................................. 48
+ 8.2.4 Applying Extensions ................................. 49
+ 8.2.5 Processing the Request .............................. 49
+
+
+
+Rosenberg, et. al. Standards Track [Page 2]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 8.2.6 Generating the Response ............................. 49
+ 8.2.6.1 Sending a Provisional Response ...................... 49
+ 8.2.6.2 Headers and Tags .................................... 50
+ 8.2.7 Stateless UAS Behavior .............................. 50
+ 8.3 Redirect Servers .................................... 51
+ 9 Canceling a Request ................................. 53
+ 9.1 Client Behavior ..................................... 53
+ 9.2 Server Behavior ..................................... 55
+ 10 Registrations ....................................... 56
+ 10.1 Overview ............................................ 56
+ 10.2 Constructing the REGISTER Request ................... 57
+ 10.2.1 Adding Bindings ..................................... 59
+ 10.2.1.1 Setting the Expiration Interval of Contact Addresses 60
+ 10.2.1.2 Preferences among Contact Addresses ................. 61
+ 10.2.2 Removing Bindings ................................... 61
+ 10.2.3 Fetching Bindings ................................... 61
+ 10.2.4 Refreshing Bindings ................................. 61
+ 10.2.5 Setting the Internal Clock .......................... 62
+ 10.2.6 Discovering a Registrar ............................. 62
+ 10.2.7 Transmitting a Request .............................. 62
+ 10.2.8 Error Responses ..................................... 63
+ 10.3 Processing REGISTER Requests ........................ 63
+ 11 Querying for Capabilities ........................... 66
+ 11.1 Construction of OPTIONS Request ..................... 67
+ 11.2 Processing of OPTIONS Request ....................... 68
+ 12 Dialogs ............................................. 69
+ 12.1 Creation of a Dialog ................................ 70
+ 12.1.1 UAS behavior ........................................ 70
+ 12.1.2 UAC Behavior ........................................ 71
+ 12.2 Requests within a Dialog ............................ 72
+ 12.2.1 UAC Behavior ........................................ 73
+ 12.2.1.1 Generating the Request .............................. 73
+ 12.2.1.2 Processing the Responses ............................ 75
+ 12.2.2 UAS Behavior ........................................ 76
+ 12.3 Termination of a Dialog ............................. 77
+ 13 Initiating a Session ................................ 77
+ 13.1 Overview ............................................ 77
+ 13.2 UAC Processing ...................................... 78
+ 13.2.1 Creating the Initial INVITE ......................... 78
+ 13.2.2 Processing INVITE Responses ......................... 81
+ 13.2.2.1 1xx Responses ....................................... 81
+ 13.2.2.2 3xx Responses ....................................... 81
+ 13.2.2.3 4xx, 5xx and 6xx Responses .......................... 81
+ 13.2.2.4 2xx Responses ....................................... 82
+ 13.3 UAS Processing ...................................... 83
+ 13.3.1 Processing of the INVITE ............................ 83
+ 13.3.1.1 Progress ............................................ 84
+ 13.3.1.2 The INVITE is Redirected ............................ 84
+
+
+
+Rosenberg, et. al. Standards Track [Page 3]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 13.3.1.3 The INVITE is Rejected .............................. 85
+ 13.3.1.4 The INVITE is Accepted .............................. 85
+ 14 Modifying an Existing Session ....................... 86
+ 14.1 UAC Behavior ........................................ 86
+ 14.2 UAS Behavior ........................................ 88
+ 15 Terminating a Session ............................... 89
+ 15.1 Terminating a Session with a BYE Request ............ 90
+ 15.1.1 UAC Behavior ........................................ 90
+ 15.1.2 UAS Behavior ........................................ 91
+ 16 Proxy Behavior ...................................... 91
+ 16.1 Overview ............................................ 91
+ 16.2 Stateful Proxy ...................................... 92
+ 16.3 Request Validation .................................. 94
+ 16.4 Route Information Preprocessing ..................... 96
+ 16.5 Determining Request Targets ......................... 97
+ 16.6 Request Forwarding .................................. 99
+ 16.7 Response Processing ................................. 107
+ 16.8 Processing Timer C .................................. 114
+ 16.9 Handling Transport Errors ........................... 115
+ 16.10 CANCEL Processing ................................... 115
+ 16.11 Stateless Proxy ..................................... 116
+ 16.12 Summary of Proxy Route Processing ................... 118
+ 16.12.1 Examples ............................................ 118
+ 16.12.1.1 Basic SIP Trapezoid ................................. 118
+ 16.12.1.2 Traversing a Strict-Routing Proxy ................... 120
+ 16.12.1.3 Rewriting Record-Route Header Field Values .......... 121
+ 17 Transactions ........................................ 122
+ 17.1 Client Transaction .................................. 124
+ 17.1.1 INVITE Client Transaction ........................... 125
+ 17.1.1.1 Overview of INVITE Transaction ...................... 125
+ 17.1.1.2 Formal Description .................................. 125
+ 17.1.1.3 Construction of the ACK Request ..................... 129
+ 17.1.2 Non-INVITE Client Transaction ....................... 130
+ 17.1.2.1 Overview of the non-INVITE Transaction .............. 130
+ 17.1.2.2 Formal Description .................................. 131
+ 17.1.3 Matching Responses to Client Transactions ........... 132
+ 17.1.4 Handling Transport Errors ........................... 133
+ 17.2 Server Transaction .................................. 134
+ 17.2.1 INVITE Server Transaction ........................... 134
+ 17.2.2 Non-INVITE Server Transaction ....................... 137
+ 17.2.3 Matching Requests to Server Transactions ............ 138
+ 17.2.4 Handling Transport Errors ........................... 141
+ 18 Transport ........................................... 141
+ 18.1 Clients ............................................. 142
+ 18.1.1 Sending Requests .................................... 142
+ 18.1.2 Receiving Responses ................................. 144
+ 18.2 Servers ............................................. 145
+ 18.2.1 Receiving Requests .................................. 145
+
+
+
+Rosenberg, et. al. Standards Track [Page 4]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 18.2.2 Sending Responses ................................... 146
+ 18.3 Framing ............................................. 147
+ 18.4 Error Handling ...................................... 147
+ 19 Common Message Components ........................... 147
+ 19.1 SIP and SIPS Uniform Resource Indicators ............ 148
+ 19.1.1 SIP and SIPS URI Components ......................... 148
+ 19.1.2 Character Escaping Requirements ..................... 152
+ 19.1.3 Example SIP and SIPS URIs ........................... 153
+ 19.1.4 URI Comparison ...................................... 153
+ 19.1.5 Forming Requests from a URI ......................... 156
+ 19.1.6 Relating SIP URIs and tel URLs ...................... 157
+ 19.2 Option Tags ......................................... 158
+ 19.3 Tags ................................................ 159
+ 20 Header Fields ....................................... 159
+ 20.1 Accept .............................................. 161
+ 20.2 Accept-Encoding ..................................... 163
+ 20.3 Accept-Language ..................................... 164
+ 20.4 Alert-Info .......................................... 164
+ 20.5 Allow ............................................... 165
+ 20.6 Authentication-Info ................................. 165
+ 20.7 Authorization ....................................... 165
+ 20.8 Call-ID ............................................. 166
+ 20.9 Call-Info ........................................... 166
+ 20.10 Contact ............................................. 167
+ 20.11 Content-Disposition ................................. 168
+ 20.12 Content-Encoding .................................... 169
+ 20.13 Content-Language .................................... 169
+ 20.14 Content-Length ...................................... 169
+ 20.15 Content-Type ........................................ 170
+ 20.16 CSeq ................................................ 170
+ 20.17 Date ................................................ 170
+ 20.18 Error-Info .......................................... 171
+ 20.19 Expires ............................................. 171
+ 20.20 From ................................................ 172
+ 20.21 In-Reply-To ......................................... 172
+ 20.22 Max-Forwards ........................................ 173
+ 20.23 Min-Expires ......................................... 173
+ 20.24 MIME-Version ........................................ 173
+ 20.25 Organization ........................................ 174
+ 20.26 Priority ............................................ 174
+ 20.27 Proxy-Authenticate .................................. 174
+ 20.28 Proxy-Authorization ................................. 175
+ 20.29 Proxy-Require ....................................... 175
+ 20.30 Record-Route ........................................ 175
+ 20.31 Reply-To ............................................ 176
+ 20.32 Require ............................................. 176
+ 20.33 Retry-After ......................................... 176
+ 20.34 Route ............................................... 177
+
+
+
+Rosenberg, et. al. Standards Track [Page 5]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 20.35 Server .............................................. 177
+ 20.36 Subject ............................................. 177
+ 20.37 Supported ........................................... 178
+ 20.38 Timestamp ........................................... 178
+ 20.39 To .................................................. 178
+ 20.40 Unsupported ......................................... 179
+ 20.41 User-Agent .......................................... 179
+ 20.42 Via ................................................. 179
+ 20.43 Warning ............................................. 180
+ 20.44 WWW-Authenticate .................................... 182
+ 21 Response Codes ...................................... 182
+ 21.1 Provisional 1xx ..................................... 182
+ 21.1.1 100 Trying .......................................... 183
+ 21.1.2 180 Ringing ......................................... 183
+ 21.1.3 181 Call Is Being Forwarded ......................... 183
+ 21.1.4 182 Queued .......................................... 183
+ 21.1.5 183 Session Progress ................................ 183
+ 21.2 Successful 2xx ...................................... 183
+ 21.2.1 200 OK .............................................. 183
+ 21.3 Redirection 3xx ..................................... 184
+ 21.3.1 300 Multiple Choices ................................ 184
+ 21.3.2 301 Moved Permanently ............................... 184
+ 21.3.3 302 Moved Temporarily ............................... 184
+ 21.3.4 305 Use Proxy ....................................... 185
+ 21.3.5 380 Alternative Service ............................. 185
+ 21.4 Request Failure 4xx ................................. 185
+ 21.4.1 400 Bad Request ..................................... 185
+ 21.4.2 401 Unauthorized .................................... 185
+ 21.4.3 402 Payment Required ................................ 186
+ 21.4.4 403 Forbidden ....................................... 186
+ 21.4.5 404 Not Found ....................................... 186
+ 21.4.6 405 Method Not Allowed .............................. 186
+ 21.4.7 406 Not Acceptable .................................. 186
+ 21.4.8 407 Proxy Authentication Required ................... 186
+ 21.4.9 408 Request Timeout ................................. 186
+ 21.4.10 410 Gone ............................................ 187
+ 21.4.11 413 Request Entity Too Large ........................ 187
+ 21.4.12 414 Request-URI Too Long ............................ 187
+ 21.4.13 415 Unsupported Media Type .......................... 187
+ 21.4.14 416 Unsupported URI Scheme .......................... 187
+ 21.4.15 420 Bad Extension ................................... 187
+ 21.4.16 421 Extension Required .............................. 188
+ 21.4.17 423 Interval Too Brief .............................. 188
+ 21.4.18 480 Temporarily Unavailable ......................... 188
+ 21.4.19 481 Call/Transaction Does Not Exist ................. 188
+ 21.4.20 482 Loop Detected ................................... 188
+ 21.4.21 483 Too Many Hops ................................... 189
+ 21.4.22 484 Address Incomplete .............................. 189
+
+
+
+Rosenberg, et. al. Standards Track [Page 6]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 21.4.23 485 Ambiguous ....................................... 189
+ 21.4.24 486 Busy Here ....................................... 189
+ 21.4.25 487 Request Terminated .............................. 190
+ 21.4.26 488 Not Acceptable Here ............................. 190
+ 21.4.27 491 Request Pending ................................. 190
+ 21.4.28 493 Undecipherable .................................. 190
+ 21.5 Server Failure 5xx .................................. 190
+ 21.5.1 500 Server Internal Error ........................... 190
+ 21.5.2 501 Not Implemented ................................. 191
+ 21.5.3 502 Bad Gateway ..................................... 191
+ 21.5.4 503 Service Unavailable ............................. 191
+ 21.5.5 504 Server Time-out ................................. 191
+ 21.5.6 505 Version Not Supported ........................... 192
+ 21.5.7 513 Message Too Large ............................... 192
+ 21.6 Global Failures 6xx ................................. 192
+ 21.6.1 600 Busy Everywhere ................................. 192
+ 21.6.2 603 Decline ......................................... 192
+ 21.6.3 604 Does Not Exist Anywhere ......................... 192
+ 21.6.4 606 Not Acceptable .................................. 192
+ 22 Usage of HTTP Authentication ........................ 193
+ 22.1 Framework ........................................... 193
+ 22.2 User-to-User Authentication ......................... 195
+ 22.3 Proxy-to-User Authentication ........................ 197
+ 22.4 The Digest Authentication Scheme .................... 199
+ 23 S/MIME .............................................. 201
+ 23.1 S/MIME Certificates ................................. 201
+ 23.2 S/MIME Key Exchange ................................. 202
+ 23.3 Securing MIME bodies ................................ 205
+ 23.4 SIP Header Privacy and Integrity using S/MIME:
+ Tunneling SIP ....................................... 207
+ 23.4.1 Integrity and Confidentiality Properties of SIP
+ Headers ............................................. 207
+ 23.4.1.1 Integrity ........................................... 207
+ 23.4.1.2 Confidentiality ..................................... 208
+ 23.4.2 Tunneling Integrity and Authentication .............. 209
+ 23.4.3 Tunneling Encryption ................................ 211
+ 24 Examples ............................................ 213
+ 24.1 Registration ........................................ 213
+ 24.2 Session Setup ....................................... 214
+ 25 Augmented BNF for the SIP Protocol .................. 219
+ 25.1 Basic Rules ......................................... 219
+ 26 Security Considerations: Threat Model and Security
+ Usage Recommendations ............................... 232
+ 26.1 Attacks and Threat Models ........................... 233
+ 26.1.1 Registration Hijacking .............................. 233
+ 26.1.2 Impersonating a Server .............................. 234
+ 26.1.3 Tampering with Message Bodies ....................... 235
+ 26.1.4 Tearing Down Sessions ............................... 235
+
+
+
+Rosenberg, et. al. Standards Track [Page 7]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 26.1.5 Denial of Service and Amplification ................. 236
+ 26.2 Security Mechanisms ................................. 237
+ 26.2.1 Transport and Network Layer Security ................ 238
+ 26.2.2 SIPS URI Scheme ..................................... 239
+ 26.2.3 HTTP Authentication ................................. 240
+ 26.2.4 S/MIME .............................................. 240
+ 26.3 Implementing Security Mechanisms .................... 241
+ 26.3.1 Requirements for Implementers of SIP ................ 241
+ 26.3.2 Security Solutions .................................. 242
+ 26.3.2.1 Registration ........................................ 242
+ 26.3.2.2 Interdomain Requests ................................ 243
+ 26.3.2.3 Peer-to-Peer Requests ............................... 245
+ 26.3.2.4 DoS Protection ...................................... 246
+ 26.4 Limitations ......................................... 247
+ 26.4.1 HTTP Digest ......................................... 247
+ 26.4.2 S/MIME .............................................. 248
+ 26.4.3 TLS ................................................. 249
+ 26.4.4 SIPS URIs ........................................... 249
+ 26.5 Privacy ............................................. 251
+ 27 IANA Considerations ................................. 252
+ 27.1 Option Tags ......................................... 252
+ 27.2 Warn-Codes .......................................... 252
+ 27.3 Header Field Names .................................. 253
+ 27.4 Method and Response Codes ........................... 253
+ 27.5 The "message/sip" MIME type. ....................... 254
+ 27.6 New Content-Disposition Parameter Registrations ..... 255
+ 28 Changes From RFC 2543 ............................... 255
+ 28.1 Major Functional Changes ............................ 255
+ 28.2 Minor Functional Changes ............................ 260
+ 29 Normative References ................................ 261
+ 30 Informative References .............................. 262
+ A Table of Timer Values ............................... 265
+ Acknowledgments ................................................ 266
+ Authors' Addresses ............................................. 267
+ Full Copyright Statement ....................................... 269
+
+1 Introduction
+
+ There are many applications of the Internet that require the creation
+ and management of a session, where a session is considered an
+ exchange of data between an association of participants. The
+ implementation of these applications is complicated by the practices
+ of participants: users may move between endpoints, they may be
+ addressable by multiple names, and they may communicate in several
+ different media - sometimes simultaneously. Numerous protocols have
+ been authored that carry various forms of real-time multimedia
+ session data such as voice, video, or text messages. The Session
+ Initiation Protocol (SIP) works in concert with these protocols by
+
+
+
+Rosenberg, et. al. Standards Track [Page 8]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ enabling Internet endpoints (called user agents) to discover one
+ another and to agree on a characterization of a session they would
+ like to share. For locating prospective session participants, and
+ for other functions, SIP enables the creation of an infrastructure of
+ network hosts (called proxy servers) to which user agents can send
+ registrations, invitations to sessions, and other requests. SIP is
+ an agile, general-purpose tool for creating, modifying, and
+ terminating sessions that works independently of underlying transport
+ protocols and without dependency on the type of session that is being
+ established.
+
+2 Overview of SIP Functionality
+
+ SIP is an application-layer control protocol that can establish,
+ modify, and terminate multimedia sessions (conferences) such as
+ Internet telephony calls. SIP can also invite participants to
+ already existing sessions, such as multicast conferences. Media can
+ be added to (and removed from) an existing session. SIP
+ transparently supports name mapping and redirection services, which
+ supports personal mobility [27] - users can maintain a single
+ externally visible identifier regardless of their network location.
+
+ SIP supports five facets of establishing and terminating multimedia
+ communications:
+
+ User location: determination of the end system to be used for
+ communication;
+
+ User availability: determination of the willingness of the called
+ party to engage in communications;
+
+ User capabilities: determination of the media and media parameters
+ to be used;
+
+ Session setup: "ringing", establishment of session parameters at
+ both called and calling party;
+
+ Session management: including transfer and termination of
+ sessions, modifying session parameters, and invoking
+ services.
+
+ SIP is not a vertically integrated communications system. SIP is
+ rather a component that can be used with other IETF protocols to
+ build a complete multimedia architecture. Typically, these
+ architectures will include protocols such as the Real-time Transport
+ Protocol (RTP) (RFC 1889 [28]) for transporting real-time data and
+ providing QoS feedback, the Real-Time streaming protocol (RTSP) (RFC
+ 2326 [29]) for controlling delivery of streaming media, the Media
+
+
+
+Rosenberg, et. al. Standards Track [Page 9]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Gateway Control Protocol (MEGACO) (RFC 3015 [30]) for controlling
+ gateways to the Public Switched Telephone Network (PSTN), and the
+ Session Description Protocol (SDP) (RFC 2327 [1]) for describing
+ multimedia sessions. Therefore, SIP should be used in conjunction
+ with other protocols in order to provide complete services to the
+ users. However, the basic functionality and operation of SIP does
+ not depend on any of these protocols.
+
+ SIP does not provide services. Rather, SIP provides primitives that
+ can be used to implement different services. For example, SIP can
+ locate a user and deliver an opaque object to his current location.
+ If this primitive is used to deliver a session description written in
+ SDP, for instance, the endpoints can agree on the parameters of a
+ session. If the same primitive is used to deliver a photo of the
+ caller as well as the session description, a "caller ID" service can
+ be easily implemented. As this example shows, a single primitive is
+ typically used to provide several different services.
+
+ SIP does not offer conference control services such as floor control
+ or voting and does not prescribe how a conference is to be managed.
+ SIP can be used to initiate a session that uses some other conference
+ control protocol. Since SIP messages and the sessions they establish
+ can pass through entirely different networks, SIP cannot, and does
+ not, provide any kind of network resource reservation capabilities.
+
+ The nature of the services provided make security particularly
+ important. To that end, SIP provides a suite of security services,
+ which include denial-of-service prevention, authentication (both user
+ to user and proxy to user), integrity protection, and encryption and
+ privacy services.
+
+ SIP works with both IPv4 and IPv6.
+
+3 Terminology
+
+ In this document, the key words "MUST", "MUST NOT", "REQUIRED",
+ "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT
+ RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as
+ described in BCP 14, RFC 2119 [2] and indicate requirement levels for
+ compliant SIP implementations.
+
+4 Overview of Operation
+
+ This section introduces the basic operations of SIP using simple
+ examples. This section is tutorial in nature and does not contain
+ any normative statements.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 10]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The first example shows the basic functions of SIP: location of an
+ end point, signal of a desire to communicate, negotiation of session
+ parameters to establish the session, and teardown of the session once
+ established.
+
+ Figure 1 shows a typical example of a SIP message exchange between
+ two users, Alice and Bob. (Each message is labeled with the letter
+ "F" and a number for reference by the text.) In this example, Alice
+ uses a SIP application on her PC (referred to as a softphone) to call
+ Bob on his SIP phone over the Internet. Also shown are two SIP proxy
+ servers that act on behalf of Alice and Bob to facilitate the session
+ establishment. This typical arrangement is often referred to as the
+ "SIP trapezoid" as shown by the geometric shape of the dotted lines
+ in Figure 1.
+
+ Alice "calls" Bob using his SIP identity, a type of Uniform Resource
+ Identifier (URI) called a SIP URI. SIP URIs are defined in Section
+ 19.1. It has a similar form to an email address, typically
+ containing a username and a host name. In this case, it is
+ sip:bob@biloxi.com, where biloxi.com is the domain of Bob's SIP
+ service provider. Alice has a SIP URI of sip:alice@atlanta.com.
+ Alice might have typed in Bob's URI or perhaps clicked on a hyperlink
+ or an entry in an address book. SIP also provides a secure URI,
+ called a SIPS URI. An example would be sips:bob@biloxi.com. A call
+ made to a SIPS URI guarantees that secure, encrypted transport
+ (namely TLS) is used to carry all SIP messages from the caller to the
+ domain of the callee. From there, the request is sent securely to
+ the callee, but with security mechanisms that depend on the policy of
+ the domain of the callee.
+
+ SIP is based on an HTTP-like request/response transaction model.
+ Each transaction consists of a request that invokes a particular
+ method, or function, on the server and at least one response. In
+ this example, the transaction begins with Alice's softphone sending
+ an INVITE request addressed to Bob's SIP URI. INVITE is an example
+ of a SIP method that specifies the action that the requestor (Alice)
+ wants the server (Bob) to take. The INVITE request contains a number
+ of header fields. Header fields are named attributes that provide
+ additional information about a message. The ones present in an
+ INVITE include a unique identifier for the call, the destination
+ address, Alice's address, and information about the type of session
+ that Alice wishes to establish with Bob. The INVITE (message F1 in
+ Figure 1) might look like this:
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 11]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ atlanta.com . . . biloxi.com
+ . proxy proxy .
+ . .
+ Alice's . . . . . . . . . . . . . . . . . . . . Bob's
+ softphone SIP Phone
+ | | | |
+ | INVITE F1 | | |
+ |--------------->| INVITE F2 | |
+ | 100 Trying F3 |--------------->| INVITE F4 |
+ |<---------------| 100 Trying F5 |--------------->|
+ | |<-------------- | 180 Ringing F6 |
+ | | 180 Ringing F7 |<---------------|
+ | 180 Ringing F8 |<---------------| 200 OK F9 |
+ |<---------------| 200 OK F10 |<---------------|
+ | 200 OK F11 |<---------------| |
+ |<---------------| | |
+ | ACK F12 |
+ |------------------------------------------------->|
+ | Media Session |
+ |<================================================>|
+ | BYE F13 |
+ |<-------------------------------------------------|
+ | 200 OK F14 |
+ |------------------------------------------------->|
+ | |
+
+ Figure 1: SIP session setup example with SIP trapezoid
+
+ INVITE sip:bob@biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds
+ Max-Forwards: 70
+ To: Bob <sip:bob@biloxi.com>
+ From: Alice <sip:alice@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710@pc33.atlanta.com
+ CSeq: 314159 INVITE
+ Contact: <sip:alice@pc33.atlanta.com>
+ Content-Type: application/sdp
+ Content-Length: 142
+
+ (Alice's SDP not shown)
+
+ The first line of the text-encoded message contains the method name
+ (INVITE). The lines that follow are a list of header fields. This
+ example contains a minimum required set. The header fields are
+ briefly described below:
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 12]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Via contains the address (pc33.atlanta.com) at which Alice is
+ expecting to receive responses to this request. It also contains a
+ branch parameter that identifies this transaction.
+
+ To contains a display name (Bob) and a SIP or SIPS URI
+ (sip:bob@biloxi.com) towards which the request was originally
+ directed. Display names are described in RFC 2822 [3].
+
+ From also contains a display name (Alice) and a SIP or SIPS URI
+ (sip:alice@atlanta.com) that indicate the originator of the request.
+ This header field also has a tag parameter containing a random string
+ (1928301774) that was added to the URI by the softphone. It is used
+ for identification purposes.
+
+ Call-ID contains a globally unique identifier for this call,
+ generated by the combination of a random string and the softphone's
+ host name or IP address. The combination of the To tag, From tag,
+ and Call-ID completely defines a peer-to-peer SIP relationship
+ between Alice and Bob and is referred to as a dialog.
+
+ CSeq or Command Sequence contains an integer and a method name. The
+ CSeq number is incremented for each new request within a dialog and
+ is a traditional sequence number.
+
+ Contact contains a SIP or SIPS URI that represents a direct route to
+ contact Alice, usually composed of a username at a fully qualified
+ domain name (FQDN). While an FQDN is preferred, many end systems do
+ not have registered domain names, so IP addresses are permitted.
+ While the Via header field tells other elements where to send the
+ response, the Contact header field tells other elements where to send
+ future requests.
+
+ Max-Forwards serves to limit the number of hops a request can make on
+ the way to its destination. It consists of an integer that is
+ decremented by one at each hop.
+
+ Content-Type contains a description of the message body (not shown).
+
+ Content-Length contains an octet (byte) count of the message body.
+
+ The complete set of SIP header fields is defined in Section 20.
+
+ The details of the session, such as the type of media, codec, or
+ sampling rate, are not described using SIP. Rather, the body of a
+ SIP message contains a description of the session, encoded in some
+ other protocol format. One such format is the Session Description
+ Protocol (SDP) (RFC 2327 [1]). This SDP message (not shown in the
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 13]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ example) is carried by the SIP message in a way that is analogous to
+ a document attachment being carried by an email message, or a web
+ page being carried in an HTTP message.
+
+ Since the softphone does not know the location of Bob or the SIP
+ server in the biloxi.com domain, the softphone sends the INVITE to
+ the SIP server that serves Alice's domain, atlanta.com. The address
+ of the atlanta.com SIP server could have been configured in Alice's
+ softphone, or it could have been discovered by DHCP, for example.
+
+ The atlanta.com SIP server is a type of SIP server known as a proxy
+ server. A proxy server receives SIP requests and forwards them on
+ behalf of the requestor. In this example, the proxy server receives
+ the INVITE request and sends a 100 (Trying) response back to Alice's
+ softphone. The 100 (Trying) response indicates that the INVITE has
+ been received and that the proxy is working on her behalf to route
+ the INVITE to the destination. Responses in SIP use a three-digit
+ code followed by a descriptive phrase. This response contains the
+ same To, From, Call-ID, CSeq and branch parameter in the Via as the
+ INVITE, which allows Alice's softphone to correlate this response to
+ the sent INVITE. The atlanta.com proxy server locates the proxy
+ server at biloxi.com, possibly by performing a particular type of DNS
+ (Domain Name Service) lookup to find the SIP server that serves the
+ biloxi.com domain. This is described in [4]. As a result, it
+ obtains the IP address of the biloxi.com proxy server and forwards,
+ or proxies, the INVITE request there. Before forwarding the request,
+ the atlanta.com proxy server adds an additional Via header field
+ value that contains its own address (the INVITE already contains
+ Alice's address in the first Via). The biloxi.com proxy server
+ receives the INVITE and responds with a 100 (Trying) response back to
+ the atlanta.com proxy server to indicate that it has received the
+ INVITE and is processing the request. The proxy server consults a
+ database, generically called a location service, that contains the
+ current IP address of Bob. (We shall see in the next section how
+ this database can be populated.) The biloxi.com proxy server adds
+ another Via header field value with its own address to the INVITE and
+ proxies it to Bob's SIP phone.
+
+ Bob's SIP phone receives the INVITE and alerts Bob to the incoming
+ call from Alice so that Bob can decide whether to answer the call,
+ that is, Bob's phone rings. Bob's SIP phone indicates this in a 180
+ (Ringing) response, which is routed back through the two proxies in
+ the reverse direction. Each proxy uses the Via header field to
+ determine where to send the response and removes its own address from
+ the top. As a result, although DNS and location service lookups were
+ required to route the initial INVITE, the 180 (Ringing) response can
+ be returned to the caller without lookups or without state being
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 14]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ maintained in the proxies. This also has the desirable property that
+ each proxy that sees the INVITE will also see all responses to the
+ INVITE.
+
+ When Alice's softphone receives the 180 (Ringing) response, it passes
+ this information to Alice, perhaps using an audio ringback tone or by
+ displaying a message on Alice's screen.
+
+ In this example, Bob decides to answer the call. When he picks up
+ the handset, his SIP phone sends a 200 (OK) response to indicate that
+ the call has been answered. The 200 (OK) contains a message body
+ with the SDP media description of the type of session that Bob is
+ willing to establish with Alice. As a result, there is a two-phase
+ exchange of SDP messages: Alice sent one to Bob, and Bob sent one
+ back to Alice. This two-phase exchange provides basic negotiation
+ capabilities and is based on a simple offer/answer model of SDP
+ exchange. If Bob did not wish to answer the call or was busy on
+ another call, an error response would have been sent instead of the
+ 200 (OK), which would have resulted in no media session being
+ established. The complete list of SIP response codes is in Section
+ 21. The 200 (OK) (message F9 in Figure 1) might look like this as
+ Bob sends it out:
+
+ SIP/2.0 200 OK
+ Via: SIP/2.0/UDP server10.biloxi.com
+ ;branch=z9hG4bKnashds8;received=192.0.2.3
+ Via: SIP/2.0/UDP bigbox3.site3.atlanta.com
+ ;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2
+ Via: SIP/2.0/UDP pc33.atlanta.com
+ ;branch=z9hG4bK776asdhds ;received=192.0.2.1
+ To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+ From: Alice <sip:alice@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710@pc33.atlanta.com
+ CSeq: 314159 INVITE
+ Contact: <sip:bob@192.0.2.4>
+ Content-Type: application/sdp
+ Content-Length: 131
+
+ (Bob's SDP not shown)
+
+ The first line of the response contains the response code (200) and
+ the reason phrase (OK). The remaining lines contain header fields.
+ The Via, To, From, Call-ID, and CSeq header fields are copied from
+ the INVITE request. (There are three Via header field values - one
+ added by Alice's SIP phone, one added by the atlanta.com proxy, and
+ one added by the biloxi.com proxy.) Bob's SIP phone has added a tag
+ parameter to the To header field. This tag will be incorporated by
+ both endpoints into the dialog and will be included in all future
+
+
+
+Rosenberg, et. al. Standards Track [Page 15]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ requests and responses in this call. The Contact header field
+ contains a URI at which Bob can be directly reached at his SIP phone.
+ The Content-Type and Content-Length refer to the message body (not
+ shown) that contains Bob's SDP media information.
+
+ In addition to DNS and location service lookups shown in this
+ example, proxy servers can make flexible "routing decisions" to
+ decide where to send a request. For example, if Bob's SIP phone
+ returned a 486 (Busy Here) response, the biloxi.com proxy server
+ could proxy the INVITE to Bob's voicemail server. A proxy server can
+ also send an INVITE to a number of locations at the same time. This
+ type of parallel search is known as forking.
+
+ In this case, the 200 (OK) is routed back through the two proxies and
+ is received by Alice's softphone, which then stops the ringback tone
+ and indicates that the call has been answered. Finally, Alice's
+ softphone sends an acknowledgement message, ACK, to Bob's SIP phone
+ to confirm the reception of the final response (200 (OK)). In this
+ example, the ACK is sent directly from Alice's softphone to Bob's SIP
+ phone, bypassing the two proxies. This occurs because the endpoints
+ have learned each other's address from the Contact header fields
+ through the INVITE/200 (OK) exchange, which was not known when the
+ initial INVITE was sent. The lookups performed by the two proxies
+ are no longer needed, so the proxies drop out of the call flow. This
+ completes the INVITE/200/ACK three-way handshake used to establish
+ SIP sessions. Full details on session setup are in Section 13.
+
+ Alice and Bob's media session has now begun, and they send media
+ packets using the format to which they agreed in the exchange of SDP.
+ In general, the end-to-end media packets take a different path from
+ the SIP signaling messages.
+
+ During the session, either Alice or Bob may decide to change the
+ characteristics of the media session. This is accomplished by
+ sending a re-INVITE containing a new media description. This re-
+ INVITE references the existing dialog so that the other party knows
+ that it is to modify an existing session instead of establishing a
+ new session. The other party sends a 200 (OK) to accept the change.
+ The requestor responds to the 200 (OK) with an ACK. If the other
+ party does not accept the change, he sends an error response such as
+ 488 (Not Acceptable Here), which also receives an ACK. However, the
+ failure of the re-INVITE does not cause the existing call to fail -
+ the session continues using the previously negotiated
+ characteristics. Full details on session modification are in Section
+ 14.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 16]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ At the end of the call, Bob disconnects (hangs up) first and
+ generates a BYE message. This BYE is routed directly to Alice's
+ softphone, again bypassing the proxies. Alice confirms receipt of
+ the BYE with a 200 (OK) response, which terminates the session and
+ the BYE transaction. No ACK is sent - an ACK is only sent in
+ response to a response to an INVITE request. The reasons for this
+ special handling for INVITE will be discussed later, but relate to
+ the reliability mechanisms in SIP, the length of time it can take for
+ a ringing phone to be answered, and forking. For this reason,
+ request handling in SIP is often classified as either INVITE or non-
+ INVITE, referring to all other methods besides INVITE. Full details
+ on session termination are in Section 15.
+
+ Section 24.2 describes the messages shown in Figure 1 in full.
+
+ In some cases, it may be useful for proxies in the SIP signaling path
+ to see all the messaging between the endpoints for the duration of
+ the session. For example, if the biloxi.com proxy server wished to
+ remain in the SIP messaging path beyond the initial INVITE, it would
+ add to the INVITE a required routing header field known as Record-
+ Route that contained a URI resolving to the hostname or IP address of
+ the proxy. This information would be received by both Bob's SIP
+ phone and (due to the Record-Route header field being passed back in
+ the 200 (OK)) Alice's softphone and stored for the duration of the
+ dialog. The biloxi.com proxy server would then receive and proxy the
+ ACK, BYE, and 200 (OK) to the BYE. Each proxy can independently
+ decide to receive subsequent messages, and those messages will pass
+ through all proxies that elect to receive it. This capability is
+ frequently used for proxies that are providing mid-call features.
+
+ Registration is another common operation in SIP. Registration is one
+ way that the biloxi.com server can learn the current location of Bob.
+ Upon initialization, and at periodic intervals, Bob's SIP phone sends
+ REGISTER messages to a server in the biloxi.com domain known as a SIP
+ registrar. The REGISTER messages associate Bob's SIP or SIPS URI
+ (sip:bob@biloxi.com) with the machine into which he is currently
+ logged (conveyed as a SIP or SIPS URI in the Contact header field).
+ The registrar writes this association, also called a binding, to a
+ database, called the location service, where it can be used by the
+ proxy in the biloxi.com domain. Often, a registrar server for a
+ domain is co-located with the proxy for that domain. It is an
+ important concept that the distinction between types of SIP servers
+ is logical, not physical.
+
+ Bob is not limited to registering from a single device. For example,
+ both his SIP phone at home and the one in the office could send
+ registrations. This information is stored together in the location
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 17]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ service and allows a proxy to perform various types of searches to
+ locate Bob. Similarly, more than one user can be registered on a
+ single device at the same time.
+
+ The location service is just an abstract concept. It generally
+ contains information that allows a proxy to input a URI and receive a
+ set of zero or more URIs that tell the proxy where to send the
+ request. Registrations are one way to create this information, but
+ not the only way. Arbitrary mapping functions can be configured at
+ the discretion of the administrator.
+
+ Finally, it is important to note that in SIP, registration is used
+ for routing incoming SIP requests and has no role in authorizing
+ outgoing requests. Authorization and authentication are handled in
+ SIP either on a request-by-request basis with a challenge/response
+ mechanism, or by using a lower layer scheme as discussed in Section
+ 26.
+
+ The complete set of SIP message details for this registration example
+ is in Section 24.1.
+
+ Additional operations in SIP, such as querying for the capabilities
+ of a SIP server or client using OPTIONS, or canceling a pending
+ request using CANCEL, will be introduced in later sections.
+
+5 Structure of the Protocol
+
+ SIP is structured as a layered protocol, which means that its
+ behavior is described in terms of a set of fairly independent
+ processing stages with only a loose coupling between each stage. The
+ protocol behavior is described as layers for the purpose of
+ presentation, allowing the description of functions common across
+ elements in a single section. It does not dictate an implementation
+ in any way. When we say that an element "contains" a layer, we mean
+ it is compliant to the set of rules defined by that layer.
+
+ Not every element specified by the protocol contains every layer.
+ Furthermore, the elements specified by SIP are logical elements, not
+ physical ones. A physical realization can choose to act as different
+ logical elements, perhaps even on a transaction-by-transaction basis.
+
+ The lowest layer of SIP is its syntax and encoding. Its encoding is
+ specified using an augmented Backus-Naur Form grammar (BNF). The
+ complete BNF is specified in Section 25; an overview of a SIP
+ message's structure can be found in Section 7.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 18]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The second layer is the transport layer. It defines how a client
+ sends requests and receives responses and how a server receives
+ requests and sends responses over the network. All SIP elements
+ contain a transport layer. The transport layer is described in
+ Section 18.
+
+ The third layer is the transaction layer. Transactions are a
+ fundamental component of SIP. A transaction is a request sent by a
+ client transaction (using the transport layer) to a server
+ transaction, along with all responses to that request sent from the
+ server transaction back to the client. The transaction layer handles
+ application-layer retransmissions, matching of responses to requests,
+ and application-layer timeouts. Any task that a user agent client
+ (UAC) accomplishes takes place using a series of transactions.
+ Discussion of transactions can be found in Section 17. User agents
+ contain a transaction layer, as do stateful proxies. Stateless
+ proxies do not contain a transaction layer. The transaction layer
+ has a client component (referred to as a client transaction) and a
+ server component (referred to as a server transaction), each of which
+ are represented by a finite state machine that is constructed to
+ process a particular request.
+
+ The layer above the transaction layer is called the transaction user
+ (TU). Each of the SIP entities, except the stateless proxy, is a
+ transaction user. When a TU wishes to send a request, it creates a
+ client transaction instance and passes it the request along with the
+ destination IP address, port, and transport to which to send the
+ request. A TU that creates a client transaction can also cancel it.
+ When a client cancels a transaction, it requests that the server stop
+ further processing, revert to the state that existed before the
+ transaction was initiated, and generate a specific error response to
+ that transaction. This is done with a CANCEL request, which
+ constitutes its own transaction, but references the transaction to be
+ cancelled (Section 9).
+
+ The SIP elements, that is, user agent clients and servers, stateless
+ and stateful proxies and registrars, contain a core that
+ distinguishes them from each other. Cores, except for the stateless
+ proxy, are transaction users. While the behavior of the UAC and UAS
+ cores depends on the method, there are some common rules for all
+ methods (Section 8). For a UAC, these rules govern the construction
+ of a request; for a UAS, they govern the processing of a request and
+ generating a response. Since registrations play an important role in
+ SIP, a UAS that handles a REGISTER is given the special name
+ registrar. Section 10 describes UAC and UAS core behavior for the
+ REGISTER method. Section 11 describes UAC and UAS core behavior for
+ the OPTIONS method, used for determining the capabilities of a UA.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 19]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Certain other requests are sent within a dialog. A dialog is a
+ peer-to-peer SIP relationship between two user agents that persists
+ for some time. The dialog facilitates sequencing of messages and
+ proper routing of requests between the user agents. The INVITE
+ method is the only way defined in this specification to establish a
+ dialog. When a UAC sends a request that is within the context of a
+ dialog, it follows the common UAC rules as discussed in Section 8 but
+ also the rules for mid-dialog requests. Section 12 discusses dialogs
+ and presents the procedures for their construction and maintenance,
+ in addition to construction of requests within a dialog.
+
+ The most important method in SIP is the INVITE method, which is used
+ to establish a session between participants. A session is a
+ collection of participants, and streams of media between them, for
+ the purposes of communication. Section 13 discusses how sessions are
+ initiated, resulting in one or more SIP dialogs. Section 14
+ discusses how characteristics of that session are modified through
+ the use of an INVITE request within a dialog. Finally, section 15
+ discusses how a session is terminated.
+
+ The procedures of Sections 8, 10, 11, 12, 13, 14, and 15 deal
+ entirely with the UA core (Section 9 describes cancellation, which
+ applies to both UA core and proxy core). Section 16 discusses the
+ proxy element, which facilitates routing of messages between user
+ agents.
+
+6 Definitions
+
+ The following terms have special significance for SIP.
+
+ Address-of-Record: An address-of-record (AOR) is a SIP or SIPS URI
+ that points to a domain with a location service that can map
+ the URI to another URI where the user might be available.
+ Typically, the location service is populated through
+ registrations. An AOR is frequently thought of as the "public
+ address" of the user.
+
+ Back-to-Back User Agent: A back-to-back user agent (B2BUA) is a
+ logical entity that receives a request and processes it as a
+ user agent server (UAS). In order to determine how the request
+ should be answered, it acts as a user agent client (UAC) and
+ generates requests. Unlike a proxy server, it maintains dialog
+ state and must participate in all requests sent on the dialogs
+ it has established. Since it is a concatenation of a UAC and
+ UAS, no explicit definitions are needed for its behavior.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 20]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Call: A call is an informal term that refers to some communication
+ between peers, generally set up for the purposes of a
+ multimedia conversation.
+
+ Call Leg: Another name for a dialog [31]; no longer used in this
+ specification.
+
+ Call Stateful: A proxy is call stateful if it retains state for a
+ dialog from the initiating INVITE to the terminating BYE
+ request. A call stateful proxy is always transaction stateful,
+ but the converse is not necessarily true.
+
+ Client: A client is any network element that sends SIP requests
+ and receives SIP responses. Clients may or may not interact
+ directly with a human user. User agent clients and proxies are
+ clients.
+
+ Conference: A multimedia session (see below) that contains
+ multiple participants.
+
+ Core: Core designates the functions specific to a particular type
+ of SIP entity, i.e., specific to either a stateful or stateless
+ proxy, a user agent or registrar. All cores, except those for
+ the stateless proxy, are transaction users.
+
+ Dialog: A dialog is a peer-to-peer SIP relationship between two
+ UAs that persists for some time. A dialog is established by
+ SIP messages, such as a 2xx response to an INVITE request. A
+ dialog is identified by a call identifier, local tag, and a
+ remote tag. A dialog was formerly known as a call leg in RFC
+ 2543.
+
+ Downstream: A direction of message forwarding within a transaction
+ that refers to the direction that requests flow from the user
+ agent client to user agent server.
+
+ Final Response: A response that terminates a SIP transaction, as
+ opposed to a provisional response that does not. All 2xx, 3xx,
+ 4xx, 5xx and 6xx responses are final.
+
+ Header: A header is a component of a SIP message that conveys
+ information about the message. It is structured as a sequence
+ of header fields.
+
+ Header Field: A header field is a component of the SIP message
+ header. A header field can appear as one or more header field
+ rows. Header field rows consist of a header field name and zero
+ or more header field values. Multiple header field values on a
+
+
+
+Rosenberg, et. al. Standards Track [Page 21]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ given header field row are separated by commas. Some header
+ fields can only have a single header field value, and as a
+ result, always appear as a single header field row.
+
+ Header Field Value: A header field value is a single value; a
+ header field consists of zero or more header field values.
+
+ Home Domain: The domain providing service to a SIP user.
+ Typically, this is the domain present in the URI in the
+ address-of-record of a registration.
+
+ Informational Response: Same as a provisional response.
+
+ Initiator, Calling Party, Caller: The party initiating a session
+ (and dialog) with an INVITE request. A caller retains this
+ role from the time it sends the initial INVITE that established
+ a dialog until the termination of that dialog.
+
+ Invitation: An INVITE request.
+
+ Invitee, Invited User, Called Party, Callee: The party that
+ receives an INVITE request for the purpose of establishing a
+ new session. A callee retains this role from the time it
+ receives the INVITE until the termination of the dialog
+ established by that INVITE.
+
+ Location Service: A location service is used by a SIP redirect or
+ proxy server to obtain information about a callee's possible
+ location(s). It contains a list of bindings of address-of-
+ record keys to zero or more contact addresses. The bindings
+ can be created and removed in many ways; this specification
+ defines a REGISTER method that updates the bindings.
+
+ Loop: A request that arrives at a proxy, is forwarded, and later
+ arrives back at the same proxy. When it arrives the second
+ time, its Request-URI is identical to the first time, and other
+ header fields that affect proxy operation are unchanged, so
+ that the proxy would make the same processing decision on the
+ request it made the first time. Looped requests are errors,
+ and the procedures for detecting them and handling them are
+ described by the protocol.
+
+ Loose Routing: A proxy is said to be loose routing if it follows
+ the procedures defined in this specification for processing of
+ the Route header field. These procedures separate the
+ destination of the request (present in the Request-URI) from
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 22]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ the set of proxies that need to be visited along the way
+ (present in the Route header field). A proxy compliant to
+ these mechanisms is also known as a loose router.
+
+ Message: Data sent between SIP elements as part of the protocol.
+ SIP messages are either requests or responses.
+
+ Method: The method is the primary function that a request is meant
+ to invoke on a server. The method is carried in the request
+ message itself. Example methods are INVITE and BYE.
+
+ Outbound Proxy: A proxy that receives requests from a client, even
+ though it may not be the server resolved by the Request-URI.
+ Typically, a UA is manually configured with an outbound proxy,
+ or can learn about one through auto-configuration protocols.
+
+ Parallel Search: In a parallel search, a proxy issues several
+ requests to possible user locations upon receiving an incoming
+ request. Rather than issuing one request and then waiting for
+ the final response before issuing the next request as in a
+ sequential search, a parallel search issues requests without
+ waiting for the result of previous requests.
+
+ Provisional Response: A response used by the server to indicate
+ progress, but that does not terminate a SIP transaction. 1xx
+ responses are provisional, other responses are considered
+ final.
+
+ Proxy, Proxy Server: An intermediary entity that acts as both a
+ server and a client for the purpose of making requests on
+ behalf of other clients. A proxy server primarily plays the
+ role of routing, which means its job is to ensure that a
+ request is sent to another entity "closer" to the targeted
+ user. Proxies are also useful for enforcing policy (for
+ example, making sure a user is allowed to make a call). A
+ proxy interprets, and, if necessary, rewrites specific parts of
+ a request message before forwarding it.
+
+ Recursion: A client recurses on a 3xx response when it generates a
+ new request to one or more of the URIs in the Contact header
+ field in the response.
+
+ Redirect Server: A redirect server is a user agent server that
+ generates 3xx responses to requests it receives, directing the
+ client to contact an alternate set of URIs.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 23]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Registrar: A registrar is a server that accepts REGISTER requests
+ and places the information it receives in those requests into
+ the location service for the domain it handles.
+
+ Regular Transaction: A regular transaction is any transaction with
+ a method other than INVITE, ACK, or CANCEL.
+
+ Request: A SIP message sent from a client to a server, for the
+ purpose of invoking a particular operation.
+
+ Response: A SIP message sent from a server to a client, for
+ indicating the status of a request sent from the client to the
+ server.
+
+ Ringback: Ringback is the signaling tone produced by the calling
+ party's application indicating that a called party is being
+ alerted (ringing).
+
+ Route Set: A route set is a collection of ordered SIP or SIPS URI
+ which represent a list of proxies that must be traversed when
+ sending a particular request. A route set can be learned,
+ through headers like Record-Route, or it can be configured.
+
+ Server: A server is a network element that receives requests in
+ order to service them and sends back responses to those
+ requests. Examples of servers are proxies, user agent servers,
+ redirect servers, and registrars.
+
+ Sequential Search: In a sequential search, a proxy server attempts
+ each contact address in sequence, proceeding to the next one
+ only after the previous has generated a final response. A 2xx
+ or 6xx class final response always terminates a sequential
+ search.
+
+ Session: From the SDP specification: "A multimedia session is a
+ set of multimedia senders and receivers and the data streams
+ flowing from senders to receivers. A multimedia conference is
+ an example of a multimedia session." (RFC 2327 [1]) (A session
+ as defined for SDP can comprise one or more RTP sessions.) As
+ defined, a callee can be invited several times, by different
+ calls, to the same session. If SDP is used, a session is
+ defined by the concatenation of the SDP user name, session id,
+ network type, address type, and address elements in the origin
+ field.
+
+ SIP Transaction: A SIP transaction occurs between a client and a
+ server and comprises all messages from the first request sent
+ from the client to the server up to a final (non-1xx) response
+
+
+
+Rosenberg, et. al. Standards Track [Page 24]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ sent from the server to the client. If the request is INVITE
+ and the final response is a non-2xx, the transaction also
+ includes an ACK to the response. The ACK for a 2xx response to
+ an INVITE request is a separate transaction.
+
+ Spiral: A spiral is a SIP request that is routed to a proxy,
+ forwarded onwards, and arrives once again at that proxy, but
+ this time differs in a way that will result in a different
+ processing decision than the original request. Typically, this
+ means that the request's Request-URI differs from its previous
+ arrival. A spiral is not an error condition, unlike a loop. A
+ typical cause for this is call forwarding. A user calls
+ joe@example.com. The example.com proxy forwards it to Joe's
+ PC, which in turn, forwards it to bob@example.com. This
+ request is proxied back to the example.com proxy. However,
+ this is not a loop. Since the request is targeted at a
+ different user, it is considered a spiral, and is a valid
+ condition.
+
+ Stateful Proxy: A logical entity that maintains the client and
+ server transaction state machines defined by this specification
+ during the processing of a request, also known as a transaction
+ stateful proxy. The behavior of a stateful proxy is further
+ defined in Section 16. A (transaction) stateful proxy is not
+ the same as a call stateful proxy.
+
+ Stateless Proxy: A logical entity that does not maintain the
+ client or server transaction state machines defined in this
+ specification when it processes requests. A stateless proxy
+ forwards every request it receives downstream and every
+ response it receives upstream.
+
+ Strict Routing: A proxy is said to be strict routing if it follows
+ the Route processing rules of RFC 2543 and many prior work in
+ progress versions of this RFC. That rule caused proxies to
+ destroy the contents of the Request-URI when a Route header
+ field was present. Strict routing behavior is not used in this
+ specification, in favor of a loose routing behavior. Proxies
+ that perform strict routing are also known as strict routers.
+
+ Target Refresh Request: A target refresh request sent within a
+ dialog is defined as a request that can modify the remote
+ target of the dialog.
+
+ Transaction User (TU): The layer of protocol processing that
+ resides above the transaction layer. Transaction users include
+ the UAC core, UAS core, and proxy core.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 25]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Upstream: A direction of message forwarding within a transaction
+ that refers to the direction that responses flow from the user
+ agent server back to the user agent client.
+
+ URL-encoded: A character string encoded according to RFC 2396,
+ Section 2.4 [5].
+
+ User Agent Client (UAC): A user agent client is a logical entity
+ that creates a new request, and then uses the client
+ transaction state machinery to send it. The role of UAC lasts
+ only for the duration of that transaction. In other words, if
+ a piece of software initiates a request, it acts as a UAC for
+ the duration of that transaction. If it receives a request
+ later, it assumes the role of a user agent server for the
+ processing of that transaction.
+
+ UAC Core: The set of processing functions required of a UAC that
+ reside above the transaction and transport layers.
+
+ User Agent Server (UAS): A user agent server is a logical entity
+ that generates a response to a SIP request. The response
+ accepts, rejects, or redirects the request. This role lasts
+ only for the duration of that transaction. In other words, if
+ a piece of software responds to a request, it acts as a UAS for
+ the duration of that transaction. If it generates a request
+ later, it assumes the role of a user agent client for the
+ processing of that transaction.
+
+ UAS Core: The set of processing functions required at a UAS that
+ resides above the transaction and transport layers.
+
+ User Agent (UA): A logical entity that can act as both a user
+ agent client and user agent server.
+
+ The role of UAC and UAS, as well as proxy and redirect servers, are
+ defined on a transaction-by-transaction basis. For example, the user
+ agent initiating a call acts as a UAC when sending the initial INVITE
+ request and as a UAS when receiving a BYE request from the callee.
+ Similarly, the same software can act as a proxy server for one
+ request and as a redirect server for the next request.
+
+ Proxy, location, and registrar servers defined above are logical
+ entities; implementations MAY combine them into a single application.
+
+7 SIP Messages
+
+ SIP is a text-based protocol and uses the UTF-8 charset (RFC 2279
+ [7]).
+
+
+
+Rosenberg, et. al. Standards Track [Page 26]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ A SIP message is either a request from a client to a server, or a
+ response from a server to a client.
+
+ Both Request (section 7.1) and Response (section 7.2) messages use
+ the basic format of RFC 2822 [3], even though the syntax differs in
+ character set and syntax specifics. (SIP allows header fields that
+ would not be valid RFC 2822 header fields, for example.) Both types
+ of messages consist of a start-line, one or more header fields, an
+ empty line indicating the end of the header fields, and an optional
+ message-body.
+
+ generic-message = start-line
+ *message-header
+ CRLF
+ [ message-body ]
+ start-line = Request-Line / Status-Line
+
+ The start-line, each message-header line, and the empty line MUST be
+ terminated by a carriage-return line-feed sequence (CRLF). Note that
+ the empty line MUST be present even if the message-body is not.
+
+ Except for the above difference in character sets, much of SIP's
+ message and header field syntax is identical to HTTP/1.1. Rather
+ than repeating the syntax and semantics here, we use [HX.Y] to refer
+ to Section X.Y of the current HTTP/1.1 specification (RFC 2616 [8]).
+
+ However, SIP is not an extension of HTTP.
+
+7.1 Requests
+
+ SIP requests are distinguished by having a Request-Line for a start-
+ line. A Request-Line contains a method name, a Request-URI, and the
+ protocol version separated by a single space (SP) character.
+
+ The Request-Line ends with CRLF. No CR or LF are allowed except in
+ the end-of-line CRLF sequence. No linear whitespace (LWS) is allowed
+ in any of the elements.
+
+ Request-Line = Method SP Request-URI SP SIP-Version CRLF
+
+ Method: This specification defines six methods: REGISTER for
+ registering contact information, INVITE, ACK, and CANCEL for
+ setting up sessions, BYE for terminating sessions, and
+ OPTIONS for querying servers about their capabilities. SIP
+ extensions, documented in standards track RFCs, may define
+ additional methods.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 27]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Request-URI: The Request-URI is a SIP or SIPS URI as described in
+ Section 19.1 or a general URI (RFC 2396 [5]). It indicates
+ the user or service to which this request is being addressed.
+ The Request-URI MUST NOT contain unescaped spaces or control
+ characters and MUST NOT be enclosed in "<>".
+
+ SIP elements MAY support Request-URIs with schemes other than
+ "sip" and "sips", for example the "tel" URI scheme of RFC
+ 2806 [9]. SIP elements MAY translate non-SIP URIs using any
+ mechanism at their disposal, resulting in SIP URI, SIPS URI,
+ or some other scheme.
+
+ SIP-Version: Both request and response messages include the
+ version of SIP in use, and follow [H3.1] (with HTTP replaced
+ by SIP, and HTTP/1.1 replaced by SIP/2.0) regarding version
+ ordering, compliance requirements, and upgrading of version
+ numbers. To be compliant with this specification,
+ applications sending SIP messages MUST include a SIP-Version
+ of "SIP/2.0". The SIP-Version string is case-insensitive,
+ but implementations MUST send upper-case.
+
+ Unlike HTTP/1.1, SIP treats the version number as a literal
+ string. In practice, this should make no difference.
+
+7.2 Responses
+
+ SIP responses are distinguished from requests by having a Status-Line
+ as their start-line. A Status-Line consists of the protocol version
+ followed by a numeric Status-Code and its associated textual phrase,
+ with each element separated by a single SP character.
+
+ No CR or LF is allowed except in the final CRLF sequence.
+
+ Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+
+ The Status-Code is a 3-digit integer result code that indicates the
+ outcome of an attempt to understand and satisfy a request. The
+ Reason-Phrase is intended to give a short textual description of the
+ Status-Code. The Status-Code is intended for use by automata,
+ whereas the Reason-Phrase is intended for the human user. A client
+ is not required to examine or display the Reason-Phrase.
+
+ While this specification suggests specific wording for the reason
+ phrase, implementations MAY choose other text, for example, in the
+ language indicated in the Accept-Language header field of the
+ request.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 28]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The first digit of the Status-Code defines the class of response.
+ The last two digits do not have any categorization role. For this
+ reason, any response with a status code between 100 and 199 is
+ referred to as a "1xx response", any response with a status code
+ between 200 and 299 as a "2xx response", and so on. SIP/2.0 allows
+ six values for the first digit:
+
+ 1xx: Provisional -- request received, continuing to process the
+ request;
+
+ 2xx: Success -- the action was successfully received, understood,
+ and accepted;
+
+ 3xx: Redirection -- further action needs to be taken in order to
+ complete the request;
+
+ 4xx: Client Error -- the request contains bad syntax or cannot be
+ fulfilled at this server;
+
+ 5xx: Server Error -- the server failed to fulfill an apparently
+ valid request;
+
+ 6xx: Global Failure -- the request cannot be fulfilled at any
+ server.
+
+ Section 21 defines these classes and describes the individual codes.
+
+7.3 Header Fields
+
+ SIP header fields are similar to HTTP header fields in both syntax
+ and semantics. In particular, SIP header fields follow the [H4.2]
+ definitions of syntax for the message-header and the rules for
+ extending header fields over multiple lines. However, the latter is
+ specified in HTTP with implicit whitespace and folding. This
+ specification conforms to RFC 2234 [10] and uses only explicit
+ whitespace and folding as an integral part of the grammar.
+
+ [H4.2] also specifies that multiple header fields of the same field
+ name whose value is a comma-separated list can be combined into one
+ header field. That applies to SIP as well, but the specific rule is
+ different because of the different grammars. Specifically, any SIP
+ header whose grammar is of the form
+
+ header = "header-name" HCOLON header-value *(COMMA header-value)
+
+ allows for combining header fields of the same name into a comma-
+ separated list. The Contact header field allows a comma-separated
+ list unless the header field value is "*".
+
+
+
+Rosenberg, et. al. Standards Track [Page 29]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+7.3.1 Header Field Format
+
+ Header fields follow the same generic header format as that given in
+ Section 2.2 of RFC 2822 [3]. Each header field consists of a field
+ name followed by a colon (":") and the field value.
+
+ field-name: field-value
+
+ The formal grammar for a message-header specified in Section 25
+ allows for an arbitrary amount of whitespace on either side of the
+ colon; however, implementations should avoid spaces between the field
+ name and the colon and use a single space (SP) between the colon and
+ the field-value.
+
+ Subject: lunch
+ Subject : lunch
+ Subject :lunch
+ Subject: lunch
+
+ Thus, the above are all valid and equivalent, but the last is the
+ preferred form.
+
+ Header fields can be extended over multiple lines by preceding each
+ extra line with at least one SP or horizontal tab (HT). The line
+ break and the whitespace at the beginning of the next line are
+ treated as a single SP character. Thus, the following are
+ equivalent:
+
+ Subject: I know you're there, pick up the phone and talk to me!
+ Subject: I know you're there,
+ pick up the phone
+ and talk to me!
+
+ The relative order of header fields with different field names is not
+ significant. However, it is RECOMMENDED that header fields which are
+ needed for proxy processing (Via, Route, Record-Route, Proxy-Require,
+ Max-Forwards, and Proxy-Authorization, for example) appear towards
+ the top of the message to facilitate rapid parsing. The relative
+ order of header field rows with the same field name is important.
+ Multiple header field rows with the same field-name MAY be present in
+ a message if and only if the entire field-value for that header field
+ is defined as a comma-separated list (that is, if follows the grammar
+ defined in Section 7.3). It MUST be possible to combine the multiple
+ header field rows into one "field-name: field-value" pair, without
+ changing the semantics of the message, by appending each subsequent
+ field-value to the first, each separated by a comma. The exceptions
+ to this rule are the WWW-Authenticate, Authorization, Proxy-
+ Authenticate, and Proxy-Authorization header fields. Multiple header
+
+
+
+Rosenberg, et. al. Standards Track [Page 30]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ field rows with these names MAY be present in a message, but since
+ their grammar does not follow the general form listed in Section 7.3,
+ they MUST NOT be combined into a single header field row.
+
+ Implementations MUST be able to process multiple header field rows
+ with the same name in any combination of the single-value-per-line or
+ comma-separated value forms.
+
+ The following groups of header field rows are valid and equivalent:
+
+ Route: <sip:alice@atlanta.com>
+ Subject: Lunch
+ Route: <sip:bob@biloxi.com>
+ Route: <sip:carol@chicago.com>
+
+ Route: <sip:alice@atlanta.com>, <sip:bob@biloxi.com>
+ Route: <sip:carol@chicago.com>
+ Subject: Lunch
+
+ Subject: Lunch
+ Route: <sip:alice@atlanta.com>, <sip:bob@biloxi.com>,
+ <sip:carol@chicago.com>
+
+ Each of the following blocks is valid but not equivalent to the
+ others:
+
+ Route: <sip:alice@atlanta.com>
+ Route: <sip:bob@biloxi.com>
+ Route: <sip:carol@chicago.com>
+
+ Route: <sip:bob@biloxi.com>
+ Route: <sip:alice@atlanta.com>
+ Route: <sip:carol@chicago.com>
+
+ Route: <sip:alice@atlanta.com>,<sip:carol@chicago.com>,
+ <sip:bob@biloxi.com>
+
+ The format of a header field-value is defined per header-name. It
+ will always be either an opaque sequence of TEXT-UTF8 octets, or a
+ combination of whitespace, tokens, separators, and quoted strings.
+ Many existing header fields will adhere to the general form of a
+ value followed by a semi-colon separated sequence of parameter-name,
+ parameter-value pairs:
+
+ field-name: field-value *(;parameter-name=parameter-value)
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 31]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Even though an arbitrary number of parameter pairs may be attached to
+ a header field value, any given parameter-name MUST NOT appear more
+ than once.
+
+ When comparing header fields, field names are always case-
+ insensitive. Unless otherwise stated in the definition of a
+ particular header field, field values, parameter names, and parameter
+ values are case-insensitive. Tokens are always case-insensitive.
+ Unless specified otherwise, values expressed as quoted strings are
+ case-sensitive. For example,
+
+ Contact: <sip:alice@atlanta.com>;expires=3600
+
+ is equivalent to
+
+ CONTACT: <sip:alice@atlanta.com>;ExPiReS=3600
+
+ and
+
+ Content-Disposition: session;handling=optional
+
+ is equivalent to
+
+ content-disposition: Session;HANDLING=OPTIONAL
+
+ The following two header fields are not equivalent:
+
+ Warning: 370 devnull "Choose a bigger pipe"
+ Warning: 370 devnull "CHOOSE A BIGGER PIPE"
+
+7.3.2 Header Field Classification
+
+ Some header fields only make sense in requests or responses. These
+ are called request header fields and response header fields,
+ respectively. If a header field appears in a message not matching
+ its category (such as a request header field in a response), it MUST
+ be ignored. Section 20 defines the classification of each header
+ field.
+
+7.3.3 Compact Form
+
+ SIP provides a mechanism to represent common header field names in an
+ abbreviated form. This may be useful when messages would otherwise
+ become too large to be carried on the transport available to it
+ (exceeding the maximum transmission unit (MTU) when using UDP, for
+ example). These compact forms are defined in Section 20. A compact
+ form MAY be substituted for the longer form of a header field name at
+ any time without changing the semantics of the message. A header
+
+
+
+Rosenberg, et. al. Standards Track [Page 32]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ field name MAY appear in both long and short forms within the same
+ message. Implementations MUST accept both the long and short forms
+ of each header name.
+
+7.4 Bodies
+
+ Requests, including new requests defined in extensions to this
+ specification, MAY contain message bodies unless otherwise noted.
+ The interpretation of the body depends on the request method.
+
+ For response messages, the request method and the response status
+ code determine the type and interpretation of any message body. All
+ responses MAY include a body.
+
+7.4.1 Message Body Type
+
+ The Internet media type of the message body MUST be given by the
+ Content-Type header field. If the body has undergone any encoding
+ such as compression, then this MUST be indicated by the Content-
+ Encoding header field; otherwise, Content-Encoding MUST be omitted.
+ If applicable, the character set of the message body is indicated as
+ part of the Content-Type header-field value.
+
+ The "multipart" MIME type defined in RFC 2046 [11] MAY be used within
+ the body of the message. Implementations that send requests
+ containing multipart message bodies MUST send a session description
+ as a non-multipart message body if the remote implementation requests
+ this through an Accept header field that does not contain multipart.
+
+ SIP messages MAY contain binary bodies or body parts. When no
+ explicit charset parameter is provided by the sender, media subtypes
+ of the "text" type are defined to have a default charset value of
+ "UTF-8".
+
+7.4.2 Message Body Length
+
+ The body length in bytes is provided by the Content-Length header
+ field. Section 20.14 describes the necessary contents of this header
+ field in detail.
+
+ The "chunked" transfer encoding of HTTP/1.1 MUST NOT be used for SIP.
+ (Note: The chunked encoding modifies the body of a message in order
+ to transfer it as a series of chunks, each with its own size
+ indicator.)
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 33]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+7.5 Framing SIP Messages
+
+ Unlike HTTP, SIP implementations can use UDP or other unreliable
+ datagram protocols. Each such datagram carries one request or
+ response. See Section 18 on constraints on usage of unreliable
+ transports.
+
+ Implementations processing SIP messages over stream-oriented
+ transports MUST ignore any CRLF appearing before the start-line
+ [H4.1].
+
+ The Content-Length header field value is used to locate the end of
+ each SIP message in a stream. It will always be present when SIP
+ messages are sent over stream-oriented transports.
+
+8 General User Agent Behavior
+
+ A user agent represents an end system. It contains a user agent
+ client (UAC), which generates requests, and a user agent server
+ (UAS), which responds to them. A UAC is capable of generating a
+ request based on some external stimulus (the user clicking a button,
+ or a signal on a PSTN line) and processing a response. A UAS is
+ capable of receiving a request and generating a response based on
+ user input, external stimulus, the result of a program execution, or
+ some other mechanism.
+
+ When a UAC sends a request, the request passes through some number of
+ proxy servers, which forward the request towards the UAS. When the
+ UAS generates a response, the response is forwarded towards the UAC.
+
+ UAC and UAS procedures depend strongly on two factors. First, based
+ on whether the request or response is inside or outside of a dialog,
+ and second, based on the method of a request. Dialogs are discussed
+ thoroughly in Section 12; they represent a peer-to-peer relationship
+ between user agents and are established by specific SIP methods, such
+ as INVITE.
+
+ In this section, we discuss the method-independent rules for UAC and
+ UAS behavior when processing requests that are outside of a dialog.
+ This includes, of course, the requests which themselves establish a
+ dialog.
+
+ Security procedures for requests and responses outside of a dialog
+ are described in Section 26. Specifically, mechanisms exist for the
+ UAS and UAC to mutually authenticate. A limited set of privacy
+ features are also supported through encryption of bodies using
+ S/MIME.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 34]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+8.1 UAC Behavior
+
+ This section covers UAC behavior outside of a dialog.
+
+8.1.1 Generating the Request
+
+ A valid SIP request formulated by a UAC MUST, at a minimum, contain
+ the following header fields: To, From, CSeq, Call-ID, Max-Forwards,
+ and Via; all of these header fields are mandatory in all SIP
+ requests. These six header fields are the fundamental building
+ blocks of a SIP message, as they jointly provide for most of the
+ critical message routing services including the addressing of
+ messages, the routing of responses, limiting message propagation,
+ ordering of messages, and the unique identification of transactions.
+ These header fields are in addition to the mandatory request line,
+ which contains the method, Request-URI, and SIP version.
+
+ Examples of requests sent outside of a dialog include an INVITE to
+ establish a session (Section 13) and an OPTIONS to query for
+ capabilities (Section 11).
+
+8.1.1.1 Request-URI
+
+ The initial Request-URI of the message SHOULD be set to the value of
+ the URI in the To field. One notable exception is the REGISTER
+ method; behavior for setting the Request-URI of REGISTER is given in
+ Section 10. It may also be undesirable for privacy reasons or
+ convenience to set these fields to the same value (especially if the
+ originating UA expects that the Request-URI will be changed during
+ transit).
+
+ In some special circumstances, the presence of a pre-existing route
+ set can affect the Request-URI of the message. A pre-existing route
+ set is an ordered set of URIs that identify a chain of servers, to
+ which a UAC will send outgoing requests that are outside of a dialog.
+ Commonly, they are configured on the UA by a user or service provider
+ manually, or through some other non-SIP mechanism. When a provider
+ wishes to configure a UA with an outbound proxy, it is RECOMMENDED
+ that this be done by providing it with a pre-existing route set with
+ a single URI, that of the outbound proxy.
+
+ When a pre-existing route set is present, the procedures for
+ populating the Request-URI and Route header field detailed in Section
+ 12.2.1.1 MUST be followed (even though there is no dialog), using the
+ desired Request-URI as the remote target URI.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 35]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+8.1.1.2 To
+
+ The To header field first and foremost specifies the desired
+ "logical" recipient of the request, or the address-of-record of the
+ user or resource that is the target of this request. This may or may
+ not be the ultimate recipient of the request. The To header field
+ MAY contain a SIP or SIPS URI, but it may also make use of other URI
+ schemes (the tel URL (RFC 2806 [9]), for example) when appropriate.
+ All SIP implementations MUST support the SIP URI scheme. Any
+ implementation that supports TLS MUST support the SIPS URI scheme.
+ The To header field allows for a display name.
+
+ A UAC may learn how to populate the To header field for a particular
+ request in a number of ways. Usually the user will suggest the To
+ header field through a human interface, perhaps inputting the URI
+ manually or selecting it from some sort of address book. Frequently,
+ the user will not enter a complete URI, but rather a string of digits
+ or letters (for example, "bob"). It is at the discretion of the UA
+ to choose how to interpret this input. Using the string to form the
+ user part of a SIP URI implies that the UA wishes the name to be
+ resolved in the domain to the right-hand side (RHS) of the at-sign in
+ the SIP URI (for instance, sip:bob@example.com). Using the string to
+ form the user part of a SIPS URI implies that the UA wishes to
+ communicate securely, and that the name is to be resolved in the
+ domain to the RHS of the at-sign. The RHS will frequently be the
+ home domain of the requestor, which allows for the home domain to
+ process the outgoing request. This is useful for features like
+ "speed dial" that require interpretation of the user part in the home
+ domain. The tel URL may be used when the UA does not wish to specify
+ the domain that should interpret a telephone number that has been
+ input by the user. Rather, each domain through which the request
+ passes would be given that opportunity. As an example, a user in an
+ airport might log in and send requests through an outbound proxy in
+ the airport. If they enter "411" (this is the phone number for local
+ directory assistance in the United States), that needs to be
+ interpreted and processed by the outbound proxy in the airport, not
+ the user's home domain. In this case, tel:411 would be the right
+ choice.
+
+ A request outside of a dialog MUST NOT contain a To tag; the tag in
+ the To field of a request identifies the peer of the dialog. Since
+ no dialog is established, no tag is present.
+
+ For further information on the To header field, see Section 20.39.
+ The following is an example of a valid To header field:
+
+ To: Carol <sip:carol@chicago.com>
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 36]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+8.1.1.3 From
+
+ The From header field indicates the logical identity of the initiator
+ of the request, possibly the user's address-of-record. Like the To
+ header field, it contains a URI and optionally a display name. It is
+ used by SIP elements to determine which processing rules to apply to
+ a request (for example, automatic call rejection). As such, it is
+ very important that the From URI not contain IP addresses or the FQDN
+ of the host on which the UA is running, since these are not logical
+ names.
+
+ The From header field allows for a display name. A UAC SHOULD use
+ the display name "Anonymous", along with a syntactically correct, but
+ otherwise meaningless URI (like sip:thisis@anonymous.invalid), if the
+ identity of the client is to remain hidden.
+
+ Usually, the value that populates the From header field in requests
+ generated by a particular UA is pre-provisioned by the user or by the
+ administrators of the user's local domain. If a particular UA is
+ used by multiple users, it might have switchable profiles that
+ include a URI corresponding to the identity of the profiled user.
+ Recipients of requests can authenticate the originator of a request
+ in order to ascertain that they are who their From header field
+ claims they are (see Section 22 for more on authentication).
+
+ The From field MUST contain a new "tag" parameter, chosen by the UAC.
+ See Section 19.3 for details on choosing a tag.
+
+ For further information on the From header field, see Section 20.20.
+ Examples:
+
+ From: "Bob" <sips:bob@biloxi.com> ;tag=a48s
+ From: sip:+12125551212@phone2net.com;tag=887s
+ From: Anonymous <sip:c8oqz84zk7z@privacy.org>;tag=hyh8
+
+8.1.1.4 Call-ID
+
+ The Call-ID header field acts as a unique identifier to group
+ together a series of messages. It MUST be the same for all requests
+ and responses sent by either UA in a dialog. It SHOULD be the same
+ in each registration from a UA.
+
+ In a new request created by a UAC outside of any dialog, the Call-ID
+ header field MUST be selected by the UAC as a globally unique
+ identifier over space and time unless overridden by method-specific
+ behavior. All SIP UAs must have a means to guarantee that the Call-
+ ID header fields they produce will not be inadvertently generated by
+ any other UA. Note that when requests are retried after certain
+
+
+
+Rosenberg, et. al. Standards Track [Page 37]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ failure responses that solicit an amendment to a request (for
+ example, a challenge for authentication), these retried requests are
+ not considered new requests, and therefore do not need new Call-ID
+ header fields; see Section 8.1.3.5.
+
+ Use of cryptographically random identifiers (RFC 1750 [12]) in the
+ generation of Call-IDs is RECOMMENDED. Implementations MAY use the
+ form "localid@host". Call-IDs are case-sensitive and are simply
+ compared byte-by-byte.
+
+ Using cryptographically random identifiers provides some
+ protection against session hijacking and reduces the likelihood of
+ unintentional Call-ID collisions.
+
+ No provisioning or human interface is required for the selection of
+ the Call-ID header field value for a request.
+
+ For further information on the Call-ID header field, see Section
+ 20.8.
+
+ Example:
+
+ Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@foo.bar.com
+
+8.1.1.5 CSeq
+
+ The CSeq header field serves as a way to identify and order
+ transactions. It consists of a sequence number and a method. The
+ method MUST match that of the request. For non-REGISTER requests
+ outside of a dialog, the sequence number value is arbitrary. The
+ sequence number value MUST be expressible as a 32-bit unsigned
+ integer and MUST be less than 2**31. As long as it follows the above
+ guidelines, a client may use any mechanism it would like to select
+ CSeq header field values.
+
+ Section 12.2.1.1 discusses construction of the CSeq for requests
+ within a dialog.
+
+ Example:
+
+ CSeq: 4711 INVITE
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 38]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+8.1.1.6 Max-Forwards
+
+ The Max-Forwards header field serves to limit the number of hops a
+ request can transit on the way to its destination. It consists of an
+ integer that is decremented by one at each hop. If the Max-Forwards
+ value reaches 0 before the request reaches its destination, it will
+ be rejected with a 483(Too Many Hops) error response.
+
+ A UAC MUST insert a Max-Forwards header field into each request it
+ originates with a value that SHOULD be 70. This number was chosen to
+ be sufficiently large to guarantee that a request would not be
+ dropped in any SIP network when there were no loops, but not so large
+ as to consume proxy resources when a loop does occur. Lower values
+ should be used with caution and only in networks where topologies are
+ known by the UA.
+
+8.1.1.7 Via
+
+ The Via header field indicates the transport used for the transaction
+ and identifies the location where the response is to be sent. A Via
+ header field value is added only after the transport that will be
+ used to reach the next hop has been selected (which may involve the
+ usage of the procedures in [4]).
+
+ When the UAC creates a request, it MUST insert a Via into that
+ request. The protocol name and protocol version in the header field
+ MUST be SIP and 2.0, respectively. The Via header field value MUST
+ contain a branch parameter. This parameter is used to identify the
+ transaction created by that request. This parameter is used by both
+ the client and the server.
+
+ The branch parameter value MUST be unique across space and time for
+ all requests sent by the UA. The exceptions to this rule are CANCEL
+ and ACK for non-2xx responses. As discussed below, a CANCEL request
+ will have the same value of the branch parameter as the request it
+ cancels. As discussed in Section 17.1.1.3, an ACK for a non-2xx
+ response will also have the same branch ID as the INVITE whose
+ response it acknowledges.
+
+ The uniqueness property of the branch ID parameter, to facilitate
+ its use as a transaction ID, was not part of RFC 2543.
+
+ The branch ID inserted by an element compliant with this
+ specification MUST always begin with the characters "z9hG4bK". These
+ 7 characters are used as a magic cookie (7 is deemed sufficient to
+ ensure that an older RFC 2543 implementation would not pick such a
+ value), so that servers receiving the request can determine that the
+ branch ID was constructed in the fashion described by this
+
+
+
+Rosenberg, et. al. Standards Track [Page 39]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ specification (that is, globally unique). Beyond this requirement,
+ the precise format of the branch token is implementation-defined.
+
+ The Via header maddr, ttl, and sent-by components will be set when
+ the request is processed by the transport layer (Section 18).
+
+ Via processing for proxies is described in Section 16.6 Item 8 and
+ Section 16.7 Item 3.
+
+8.1.1.8 Contact
+
+ The Contact header field provides a SIP or SIPS URI that can be used
+ to contact that specific instance of the UA for subsequent requests.
+ The Contact header field MUST be present and contain exactly one SIP
+ or SIPS URI in any request that can result in the establishment of a
+ dialog. For the methods defined in this specification, that includes
+ only the INVITE request. For these requests, the scope of the
+ Contact is global. That is, the Contact header field value contains
+ the URI at which the UA would like to receive requests, and this URI
+ MUST be valid even if used in subsequent requests outside of any
+ dialogs.
+
+ If the Request-URI or top Route header field value contains a SIPS
+ URI, the Contact header field MUST contain a SIPS URI as well.
+
+ For further information on the Contact header field, see Section
+ 20.10.
+
+8.1.1.9 Supported and Require
+
+ If the UAC supports extensions to SIP that can be applied by the
+ server to the response, the UAC SHOULD include a Supported header
+ field in the request listing the option tags (Section 19.2) for those
+ extensions.
+
+ The option tags listed MUST only refer to extensions defined in
+ standards-track RFCs. This is to prevent servers from insisting that
+ clients implement non-standard, vendor-defined features in order to
+ receive service. Extensions defined by experimental and
+ informational RFCs are explicitly excluded from usage with the
+ Supported header field in a request, since they too are often used to
+ document vendor-defined extensions.
+
+ If the UAC wishes to insist that a UAS understand an extension that
+ the UAC will apply to the request in order to process the request, it
+ MUST insert a Require header field into the request listing the
+ option tag for that extension. If the UAC wishes to apply an
+ extension to the request and insist that any proxies that are
+
+
+
+Rosenberg, et. al. Standards Track [Page 40]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ traversed understand that extension, it MUST insert a Proxy-Require
+ header field into the request listing the option tag for that
+ extension.
+
+ As with the Supported header field, the option tags in the Require
+ and Proxy-Require header fields MUST only refer to extensions defined
+ in standards-track RFCs.
+
+8.1.1.10 Additional Message Components
+
+ After a new request has been created, and the header fields described
+ above have been properly constructed, any additional optional header
+ fields are added, as are any header fields specific to the method.
+
+ SIP requests MAY contain a MIME-encoded message-body. Regardless of
+ the type of body that a request contains, certain header fields must
+ be formulated to characterize the contents of the body. For further
+ information on these header fields, see Sections 20.11 through 20.15.
+
+8.1.2 Sending the Request
+
+ The destination for the request is then computed. Unless there is
+ local policy specifying otherwise, the destination MUST be determined
+ by applying the DNS procedures described in [4] as follows. If the
+ first element in the route set indicated a strict router (resulting
+ in forming the request as described in Section 12.2.1.1), the
+ procedures MUST be applied to the Request-URI of the request.
+ Otherwise, the procedures are applied to the first Route header field
+ value in the request (if one exists), or to the request's Request-URI
+ if there is no Route header field present. These procedures yield an
+ ordered set of address, port, and transports to attempt. Independent
+ of which URI is used as input to the procedures of [4], if the
+ Request-URI specifies a SIPS resource, the UAC MUST follow the
+ procedures of [4] as if the input URI were a SIPS URI.
+
+ Local policy MAY specify an alternate set of destinations to attempt.
+ If the Request-URI contains a SIPS URI, any alternate destinations
+ MUST be contacted with TLS. Beyond that, there are no restrictions
+ on the alternate destinations if the request contains no Route header
+ field. This provides a simple alternative to a pre-existing route
+ set as a way to specify an outbound proxy. However, that approach
+ for configuring an outbound proxy is NOT RECOMMENDED; a pre-existing
+ route set with a single URI SHOULD be used instead. If the request
+ contains a Route header field, the request SHOULD be sent to the
+ locations derived from its topmost value, but MAY be sent to any
+ server that the UA is certain will honor the Route and Request-URI
+ policies specified in this document (as opposed to those in RFC
+ 2543). In particular, a UAC configured with an outbound proxy SHOULD
+
+
+
+Rosenberg, et. al. Standards Track [Page 41]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ attempt to send the request to the location indicated in the first
+ Route header field value instead of adopting the policy of sending
+ all messages to the outbound proxy.
+
+ This ensures that outbound proxies that do not add Record-Route
+ header field values will drop out of the path of subsequent
+ requests. It allows endpoints that cannot resolve the first Route
+ URI to delegate that task to an outbound proxy.
+
+ The UAC SHOULD follow the procedures defined in [4] for stateful
+ elements, trying each address until a server is contacted. Each try
+ constitutes a new transaction, and therefore each carries a different
+ topmost Via header field value with a new branch parameter.
+ Furthermore, the transport value in the Via header field is set to
+ whatever transport was determined for the target server.
+
+8.1.3 Processing Responses
+
+ Responses are first processed by the transport layer and then passed
+ up to the transaction layer. The transaction layer performs its
+ processing and then passes the response up to the TU. The majority
+ of response processing in the TU is method specific. However, there
+ are some general behaviors independent of the method.
+
+8.1.3.1 Transaction Layer Errors
+
+ In some cases, the response returned by the transaction layer will
+ not be a SIP message, but rather a transaction layer error. When a
+ timeout error is received from the transaction layer, it MUST be
+ treated as if a 408 (Request Timeout) status code has been received.
+ If a fatal transport error is reported by the transport layer
+ (generally, due to fatal ICMP errors in UDP or connection failures in
+ TCP), the condition MUST be treated as a 503 (Service Unavailable)
+ status code.
+
+8.1.3.2 Unrecognized Responses
+
+ A UAC MUST treat any final response it does not recognize as being
+ equivalent to the x00 response code of that class, and MUST be able
+ to process the x00 response code for all classes. For example, if a
+ UAC receives an unrecognized response code of 431, it can safely
+ assume that there was something wrong with its request and treat the
+ response as if it had received a 400 (Bad Request) response code. A
+ UAC MUST treat any provisional response different than 100 that it
+ does not recognize as 183 (Session Progress). A UAC MUST be able to
+ process 100 and 183 responses.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 42]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+8.1.3.3 Vias
+
+ If more than one Via header field value is present in a response, the
+ UAC SHOULD discard the message.
+
+ The presence of additional Via header field values that precede
+ the originator of the request suggests that the message was
+ misrouted or possibly corrupted.
+
+8.1.3.4 Processing 3xx Responses
+
+ Upon receipt of a redirection response (for example, a 301 response
+ status code), clients SHOULD use the URI(s) in the Contact header
+ field to formulate one or more new requests based on the redirected
+ request. This process is similar to that of a proxy recursing on a
+ 3xx class response as detailed in Sections 16.5 and 16.6. A client
+ starts with an initial target set containing exactly one URI, the
+ Request-URI of the original request. If a client wishes to formulate
+ new requests based on a 3xx class response to that request, it places
+ the URIs to try into the target set. Subject to the restrictions in
+ this specification, a client can choose which Contact URIs it places
+ into the target set. As with proxy recursion, a client processing
+ 3xx class responses MUST NOT add any given URI to the target set more
+ than once. If the original request had a SIPS URI in the Request-
+ URI, the client MAY choose to recurse to a non-SIPS URI, but SHOULD
+ inform the user of the redirection to an insecure URI.
+
+ Any new request may receive 3xx responses themselves containing
+ the original URI as a contact. Two locations can be configured to
+ redirect to each other. Placing any given URI in the target set
+ only once prevents infinite redirection loops.
+
+ As the target set grows, the client MAY generate new requests to the
+ URIs in any order. A common mechanism is to order the set by the "q"
+ parameter value from the Contact header field value. Requests to the
+ URIs MAY be generated serially or in parallel. One approach is to
+ process groups of decreasing q-values serially and process the URIs
+ in each q-value group in parallel. Another is to perform only serial
+ processing in decreasing q-value order, arbitrarily choosing between
+ contacts of equal q-value.
+
+ If contacting an address in the list results in a failure, as defined
+ in the next paragraph, the element moves to the next address in the
+ list, until the list is exhausted. If the list is exhausted, then
+ the request has failed.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 43]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Failures SHOULD be detected through failure response codes (codes
+ greater than 399); for network errors the client transaction will
+ report any transport layer failures to the transaction user. Note
+ that some response codes (detailed in 8.1.3.5) indicate that the
+ request can be retried; requests that are reattempted should not be
+ considered failures.
+
+ When a failure for a particular contact address is received, the
+ client SHOULD try the next contact address. This will involve
+ creating a new client transaction to deliver a new request.
+
+ In order to create a request based on a contact address in a 3xx
+ response, a UAC MUST copy the entire URI from the target set into the
+ Request-URI, except for the "method-param" and "header" URI
+ parameters (see Section 19.1.1 for a definition of these parameters).
+ It uses the "header" parameters to create header field values for the
+ new request, overwriting header field values associated with the
+ redirected request in accordance with the guidelines in Section
+ 19.1.5.
+
+ Note that in some instances, header fields that have been
+ communicated in the contact address may instead append to existing
+ request header fields in the original redirected request. As a
+ general rule, if the header field can accept a comma-separated list
+ of values, then the new header field value MAY be appended to any
+ existing values in the original redirected request. If the header
+ field does not accept multiple values, the value in the original
+ redirected request MAY be overwritten by the header field value
+ communicated in the contact address. For example, if a contact
+ address is returned with the following value:
+
+ sip:user@host?Subject=foo&Call-Info=<http://www.foo.com>
+
+ Then any Subject header field in the original redirected request is
+ overwritten, but the HTTP URL is merely appended to any existing
+ Call-Info header field values.
+
+ It is RECOMMENDED that the UAC reuse the same To, From, and Call-ID
+ used in the original redirected request, but the UAC MAY also choose
+ to update the Call-ID header field value for new requests, for
+ example.
+
+ Finally, once the new request has been constructed, it is sent using
+ a new client transaction, and therefore MUST have a new branch ID in
+ the top Via field as discussed in Section 8.1.1.7.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 44]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ In all other respects, requests sent upon receipt of a redirect
+ response SHOULD re-use the header fields and bodies of the original
+ request.
+
+ In some instances, Contact header field values may be cached at UAC
+ temporarily or permanently depending on the status code received and
+ the presence of an expiration interval; see Sections 21.3.2 and
+ 21.3.3.
+
+8.1.3.5 Processing 4xx Responses
+
+ Certain 4xx response codes require specific UA processing,
+ independent of the method.
+
+ If a 401 (Unauthorized) or 407 (Proxy Authentication Required)
+ response is received, the UAC SHOULD follow the authorization
+ procedures of Section 22.2 and Section 22.3 to retry the request with
+ credentials.
+
+ If a 413 (Request Entity Too Large) response is received (Section
+ 21.4.11), the request contained a body that was longer than the UAS
+ was willing to accept. If possible, the UAC SHOULD retry the
+ request, either omitting the body or using one of a smaller length.
+
+ If a 415 (Unsupported Media Type) response is received (Section
+ 21.4.13), the request contained media types not supported by the UAS.
+ The UAC SHOULD retry sending the request, this time only using
+ content with types listed in the Accept header field in the response,
+ with encodings listed in the Accept-Encoding header field in the
+ response, and with languages listed in the Accept-Language in the
+ response.
+
+ If a 416 (Unsupported URI Scheme) response is received (Section
+ 21.4.14), the Request-URI used a URI scheme not supported by the
+ server. The client SHOULD retry the request, this time, using a SIP
+ URI.
+
+ If a 420 (Bad Extension) response is received (Section 21.4.15), the
+ request contained a Require or Proxy-Require header field listing an
+ option-tag for a feature not supported by a proxy or UAS. The UAC
+ SHOULD retry the request, this time omitting any extensions listed in
+ the Unsupported header field in the response.
+
+ In all of the above cases, the request is retried by creating a new
+ request with the appropriate modifications. This new request
+ constitutes a new transaction and SHOULD have the same value of the
+ Call-ID, To, and From of the previous request, but the CSeq should
+ contain a new sequence number that is one higher than the previous.
+
+
+
+Rosenberg, et. al. Standards Track [Page 45]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ With other 4xx responses, including those yet to be defined, a retry
+ may or may not be possible depending on the method and the use case.
+
+8.2 UAS Behavior
+
+ When a request outside of a dialog is processed by a UAS, there is a
+ set of processing rules that are followed, independent of the method.
+ Section 12 gives guidance on how a UAS can tell whether a request is
+ inside or outside of a dialog.
+
+ Note that request processing is atomic. If a request is accepted,
+ all state changes associated with it MUST be performed. If it is
+ rejected, all state changes MUST NOT be performed.
+
+ UASs SHOULD process the requests in the order of the steps that
+ follow in this section (that is, starting with authentication, then
+ inspecting the method, the header fields, and so on throughout the
+ remainder of this section).
+
+8.2.1 Method Inspection
+
+ Once a request is authenticated (or authentication is skipped), the
+ UAS MUST inspect the method of the request. If the UAS recognizes
+ but does not support the method of a request, it MUST generate a 405
+ (Method Not Allowed) response. Procedures for generating responses
+ are described in Section 8.2.6. The UAS MUST also add an Allow
+ header field to the 405 (Method Not Allowed) response. The Allow
+ header field MUST list the set of methods supported by the UAS
+ generating the message. The Allow header field is presented in
+ Section 20.5.
+
+ If the method is one supported by the server, processing continues.
+
+8.2.2 Header Inspection
+
+ If a UAS does not understand a header field in a request (that is,
+ the header field is not defined in this specification or in any
+ supported extension), the server MUST ignore that header field and
+ continue processing the message. A UAS SHOULD ignore any malformed
+ header fields that are not necessary for processing requests.
+
+8.2.2.1 To and Request-URI
+
+ The To header field identifies the original recipient of the request
+ designated by the user identified in the From field. The original
+ recipient may or may not be the UAS processing the request, due to
+ call forwarding or other proxy operations. A UAS MAY apply any
+ policy it wishes to determine whether to accept requests when the To
+
+
+
+Rosenberg, et. al. Standards Track [Page 46]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ header field is not the identity of the UAS. However, it is
+ RECOMMENDED that a UAS accept requests even if they do not recognize
+ the URI scheme (for example, a tel: URI) in the To header field, or
+ if the To header field does not address a known or current user of
+ this UAS. If, on the other hand, the UAS decides to reject the
+ request, it SHOULD generate a response with a 403 (Forbidden) status
+ code and pass it to the server transaction for transmission.
+
+ However, the Request-URI identifies the UAS that is to process the
+ request. If the Request-URI uses a scheme not supported by the UAS,
+ it SHOULD reject the request with a 416 (Unsupported URI Scheme)
+ response. If the Request-URI does not identify an address that the
+ UAS is willing to accept requests for, it SHOULD reject the request
+ with a 404 (Not Found) response. Typically, a UA that uses the
+ REGISTER method to bind its address-of-record to a specific contact
+ address will see requests whose Request-URI equals that contact
+ address. Other potential sources of received Request-URIs include
+ the Contact header fields of requests and responses sent by the UA
+ that establish or refresh dialogs.
+
+8.2.2.2 Merged Requests
+
+ If the request has no tag in the To header field, the UAS core MUST
+ check the request against ongoing transactions. If the From tag,
+ Call-ID, and CSeq exactly match those associated with an ongoing
+ transaction, but the request does not match that transaction (based
+ on the matching rules in Section 17.2.3), the UAS core SHOULD
+ generate a 482 (Loop Detected) response and pass it to the server
+ transaction.
+
+ The same request has arrived at the UAS more than once, following
+ different paths, most likely due to forking. The UAS processes
+ the first such request received and responds with a 482 (Loop
+ Detected) to the rest of them.
+
+8.2.2.3 Require
+
+ Assuming the UAS decides that it is the proper element to process the
+ request, it examines the Require header field, if present.
+
+ The Require header field is used by a UAC to tell a UAS about SIP
+ extensions that the UAC expects the UAS to support in order to
+ process the request properly. Its format is described in Section
+ 20.32. If a UAS does not understand an option-tag listed in a
+ Require header field, it MUST respond by generating a response with
+ status code 420 (Bad Extension). The UAS MUST add an Unsupported
+ header field, and list in it those options it does not understand
+ amongst those in the Require header field of the request.
+
+
+
+Rosenberg, et. al. Standards Track [Page 47]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Note that Require and Proxy-Require MUST NOT be used in a SIP CANCEL
+ request, or in an ACK request sent for a non-2xx response. These
+ header fields MUST be ignored if they are present in these requests.
+
+ An ACK request for a 2xx response MUST contain only those Require and
+ Proxy-Require values that were present in the initial request.
+
+ Example:
+
+ UAC->UAS: INVITE sip:watson@bell-telephone.com SIP/2.0
+ Require: 100rel
+
+ UAS->UAC: SIP/2.0 420 Bad Extension
+ Unsupported: 100rel
+
+ This behavior ensures that the client-server interaction will
+ proceed without delay when all options are understood by both
+ sides, and only slow down if options are not understood (as in the
+ example above). For a well-matched client-server pair, the
+ interaction proceeds quickly, saving a round-trip often required
+ by negotiation mechanisms. In addition, it also removes ambiguity
+ when the client requires features that the server does not
+ understand. Some features, such as call handling fields, are only
+ of interest to end systems.
+
+8.2.3 Content Processing
+
+ Assuming the UAS understands any extensions required by the client,
+ the UAS examines the body of the message, and the header fields that
+ describe it. If there are any bodies whose type (indicated by the
+ Content-Type), language (indicated by the Content-Language) or
+ encoding (indicated by the Content-Encoding) are not understood, and
+ that body part is not optional (as indicated by the Content-
+ Disposition header field), the UAS MUST reject the request with a 415
+ (Unsupported Media Type) response. The response MUST contain an
+ Accept header field listing the types of all bodies it understands,
+ in the event the request contained bodies of types not supported by
+ the UAS. If the request contained content encodings not understood
+ by the UAS, the response MUST contain an Accept-Encoding header field
+ listing the encodings understood by the UAS. If the request
+ contained content with languages not understood by the UAS, the
+ response MUST contain an Accept-Language header field indicating the
+ languages understood by the UAS. Beyond these checks, body handling
+ depends on the method and type. For further information on the
+ processing of content-specific header fields, see Section 7.4 as well
+ as Section 20.11 through 20.15.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 48]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+8.2.4 Applying Extensions
+
+ A UAS that wishes to apply some extension when generating the
+ response MUST NOT do so unless support for that extension is
+ indicated in the Supported header field in the request. If the
+ desired extension is not supported, the server SHOULD rely only on
+ baseline SIP and any other extensions supported by the client. In
+ rare circumstances, where the server cannot process the request
+ without the extension, the server MAY send a 421 (Extension Required)
+ response. This response indicates that the proper response cannot be
+ generated without support of a specific extension. The needed
+ extension(s) MUST be included in a Require header field in the
+ response. This behavior is NOT RECOMMENDED, as it will generally
+ break interoperability.
+
+ Any extensions applied to a non-421 response MUST be listed in a
+ Require header field included in the response. Of course, the server
+ MUST NOT apply extensions not listed in the Supported header field in
+ the request. As a result of this, the Require header field in a
+ response will only ever contain option tags defined in standards-
+ track RFCs.
+
+8.2.5 Processing the Request
+
+ Assuming all of the checks in the previous subsections are passed,
+ the UAS processing becomes method-specific. Section 10 covers the
+ REGISTER request, Section 11 covers the OPTIONS request, Section 13
+ covers the INVITE request, and Section 15 covers the BYE request.
+
+8.2.6 Generating the Response
+
+ When a UAS wishes to construct a response to a request, it follows
+ the general procedures detailed in the following subsections.
+ Additional behaviors specific to the response code in question, which
+ are not detailed in this section, may also be required.
+
+ Once all procedures associated with the creation of a response have
+ been completed, the UAS hands the response back to the server
+ transaction from which it received the request.
+
+8.2.6.1 Sending a Provisional Response
+
+ One largely non-method-specific guideline for the generation of
+ responses is that UASs SHOULD NOT issue a provisional response for a
+ non-INVITE request. Rather, UASs SHOULD generate a final response to
+ a non-INVITE request as soon as possible.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 49]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ When a 100 (Trying) response is generated, any Timestamp header field
+ present in the request MUST be copied into this 100 (Trying)
+ response. If there is a delay in generating the response, the UAS
+ SHOULD add a delay value into the Timestamp value in the response.
+ This value MUST contain the difference between the time of sending of
+ the response and receipt of the request, measured in seconds.
+
+8.2.6.2 Headers and Tags
+
+ The From field of the response MUST equal the From header field of
+ the request. The Call-ID header field of the response MUST equal the
+ Call-ID header field of the request. The CSeq header field of the
+ response MUST equal the CSeq field of the request. The Via header
+ field values in the response MUST equal the Via header field values
+ in the request and MUST maintain the same ordering.
+
+ If a request contained a To tag in the request, the To header field
+ in the response MUST equal that of the request. However, if the To
+ header field in the request did not contain a tag, the URI in the To
+ header field in the response MUST equal the URI in the To header
+ field; additionally, the UAS MUST add a tag to the To header field in
+ the response (with the exception of the 100 (Trying) response, in
+ which a tag MAY be present). This serves to identify the UAS that is
+ responding, possibly resulting in a component of a dialog ID. The
+ same tag MUST be used for all responses to that request, both final
+ and provisional (again excepting the 100 (Trying)). Procedures for
+ the generation of tags are defined in Section 19.3.
+
+8.2.7 Stateless UAS Behavior
+
+ A stateless UAS is a UAS that does not maintain transaction state.
+ It replies to requests normally, but discards any state that would
+ ordinarily be retained by a UAS after a response has been sent. If a
+ stateless UAS receives a retransmission of a request, it regenerates
+ the response and resends it, just as if it were replying to the first
+ instance of the request. A UAS cannot be stateless unless the request
+ processing for that method would always result in the same response
+ if the requests are identical. This rules out stateless registrars,
+ for example. Stateless UASs do not use a transaction layer; they
+ receive requests directly from the transport layer and send responses
+ directly to the transport layer.
+
+ The stateless UAS role is needed primarily to handle unauthenticated
+ requests for which a challenge response is issued. If
+ unauthenticated requests were handled statefully, then malicious
+ floods of unauthenticated requests could create massive amounts of
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 50]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ transaction state that might slow or completely halt call processing
+ in a UAS, effectively creating a denial of service condition; for
+ more information see Section 26.1.5.
+
+ The most important behaviors of a stateless UAS are the following:
+
+ o A stateless UAS MUST NOT send provisional (1xx) responses.
+
+ o A stateless UAS MUST NOT retransmit responses.
+
+ o A stateless UAS MUST ignore ACK requests.
+
+ o A stateless UAS MUST ignore CANCEL requests.
+
+ o To header tags MUST be generated for responses in a stateless
+ manner - in a manner that will generate the same tag for the
+ same request consistently. For information on tag construction
+ see Section 19.3.
+
+ In all other respects, a stateless UAS behaves in the same manner as
+ a stateful UAS. A UAS can operate in either a stateful or stateless
+ mode for each new request.
+
+8.3 Redirect Servers
+
+ In some architectures it may be desirable to reduce the processing
+ load on proxy servers that are responsible for routing requests, and
+ improve signaling path robustness, by relying on redirection.
+
+ Redirection allows servers to push routing information for a request
+ back in a response to the client, thereby taking themselves out of
+ the loop of further messaging for this transaction while still aiding
+ in locating the target of the request. When the originator of the
+ request receives the redirection, it will send a new request based on
+ the URI(s) it has received. By propagating URIs from the core of the
+ network to its edges, redirection allows for considerable network
+ scalability.
+
+ A redirect server is logically constituted of a server transaction
+ layer and a transaction user that has access to a location service of
+ some kind (see Section 10 for more on registrars and location
+ services). This location service is effectively a database
+ containing mappings between a single URI and a set of one or more
+ alternative locations at which the target of that URI can be found.
+
+ A redirect server does not issue any SIP requests of its own. After
+ receiving a request other than CANCEL, the server either refuses the
+ request or gathers the list of alternative locations from the
+
+
+
+Rosenberg, et. al. Standards Track [Page 51]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ location service and returns a final response of class 3xx. For
+ well-formed CANCEL requests, it SHOULD return a 2xx response. This
+ response ends the SIP transaction. The redirect server maintains
+ transaction state for an entire SIP transaction. It is the
+ responsibility of clients to detect forwarding loops between redirect
+ servers.
+
+ When a redirect server returns a 3xx response to a request, it
+ populates the list of (one or more) alternative locations into the
+ Contact header field. An "expires" parameter to the Contact header
+ field values may also be supplied to indicate the lifetime of the
+ Contact data.
+
+ The Contact header field contains URIs giving the new locations or
+ user names to try, or may simply specify additional transport
+ parameters. A 301 (Moved Permanently) or 302 (Moved Temporarily)
+ response may also give the same location and username that was
+ targeted by the initial request but specify additional transport
+ parameters such as a different server or multicast address to try, or
+ a change of SIP transport from UDP to TCP or vice versa.
+
+ However, redirect servers MUST NOT redirect a request to a URI equal
+ to the one in the Request-URI; instead, provided that the URI does
+ not point to itself, the server MAY proxy the request to the
+ destination URI, or MAY reject it with a 404.
+
+ If a client is using an outbound proxy, and that proxy actually
+ redirects requests, a potential arises for infinite redirection
+ loops.
+
+ Note that a Contact header field value MAY also refer to a different
+ resource than the one originally called. For example, a SIP call
+ connected to PSTN gateway may need to deliver a special informational
+ announcement such as "The number you have dialed has been changed."
+
+ A Contact response header field can contain any suitable URI
+ indicating where the called party can be reached, not limited to SIP
+ URIs. For example, it could contain URIs for phones, fax, or irc (if
+ they were defined) or a mailto: (RFC 2368 [32]) URL. Section 26.4.4
+ discusses implications and limitations of redirecting a SIPS URI to a
+ non-SIPS URI.
+
+ The "expires" parameter of a Contact header field value indicates how
+ long the URI is valid. The value of the parameter is a number
+ indicating seconds. If this parameter is not provided, the value of
+ the Expires header field determines how long the URI is valid.
+ Malformed values SHOULD be treated as equivalent to 3600.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 52]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ This provides a modest level of backwards compatibility with RFC
+ 2543, which allowed absolute times in this header field. If an
+ absolute time is received, it will be treated as malformed, and
+ then default to 3600.
+
+ Redirect servers MUST ignore features that are not understood
+ (including unrecognized header fields, any unknown option tags in
+ Require, or even method names) and proceed with the redirection of
+ the request in question.
+
+9 Canceling a Request
+
+ The previous section has discussed general UA behavior for generating
+ requests and processing responses for requests of all methods. In
+ this section, we discuss a general purpose method, called CANCEL.
+
+ The CANCEL request, as the name implies, is used to cancel a previous
+ request sent by a client. Specifically, it asks the UAS to cease
+ processing the request and to generate an error response to that
+ request. CANCEL has no effect on a request to which a UAS has
+ already given a final response. Because of this, it is most useful
+ to CANCEL requests to which it can take a server long time to
+ respond. For this reason, CANCEL is best for INVITE requests, which
+ can take a long time to generate a response. In that usage, a UAS
+ that receives a CANCEL request for an INVITE, but has not yet sent a
+ final response, would "stop ringing", and then respond to the INVITE
+ with a specific error response (a 487).
+
+ CANCEL requests can be constructed and sent by both proxies and user
+ agent clients. Section 15 discusses under what conditions a UAC
+ would CANCEL an INVITE request, and Section 16.10 discusses proxy
+ usage of CANCEL.
+
+ A stateful proxy responds to a CANCEL, rather than simply forwarding
+ a response it would receive from a downstream element. For that
+ reason, CANCEL is referred to as a "hop-by-hop" request, since it is
+ responded to at each stateful proxy hop.
+
+9.1 Client Behavior
+
+ A CANCEL request SHOULD NOT be sent to cancel a request other than
+ INVITE.
+
+ Since requests other than INVITE are responded to immediately,
+ sending a CANCEL for a non-INVITE request would always create a
+ race condition.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 53]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The following procedures are used to construct a CANCEL request. The
+ Request-URI, Call-ID, To, the numeric part of CSeq, and From header
+ fields in the CANCEL request MUST be identical to those in the
+ request being cancelled, including tags. A CANCEL constructed by a
+ client MUST have only a single Via header field value matching the
+ top Via value in the request being cancelled. Using the same values
+ for these header fields allows the CANCEL to be matched with the
+ request it cancels (Section 9.2 indicates how such matching occurs).
+ However, the method part of the CSeq header field MUST have a value
+ of CANCEL. This allows it to be identified and processed as a
+ transaction in its own right (See Section 17).
+
+ If the request being cancelled contains a Route header field, the
+ CANCEL request MUST include that Route header field's values.
+
+ This is needed so that stateless proxies are able to route CANCEL
+ requests properly.
+
+ The CANCEL request MUST NOT contain any Require or Proxy-Require
+ header fields.
+
+ Once the CANCEL is constructed, the client SHOULD check whether it
+ has received any response (provisional or final) for the request
+ being cancelled (herein referred to as the "original request").
+
+ If no provisional response has been received, the CANCEL request MUST
+ NOT be sent; rather, the client MUST wait for the arrival of a
+ provisional response before sending the request. If the original
+ request has generated a final response, the CANCEL SHOULD NOT be
+ sent, as it is an effective no-op, since CANCEL has no effect on
+ requests that have already generated a final response. When the
+ client decides to send the CANCEL, it creates a client transaction
+ for the CANCEL and passes it the CANCEL request along with the
+ destination address, port, and transport. The destination address,
+ port, and transport for the CANCEL MUST be identical to those used to
+ send the original request.
+
+ If it was allowed to send the CANCEL before receiving a response
+ for the previous request, the server could receive the CANCEL
+ before the original request.
+
+ Note that both the transaction corresponding to the original request
+ and the CANCEL transaction will complete independently. However, a
+ UAC canceling a request cannot rely on receiving a 487 (Request
+ Terminated) response for the original request, as an RFC 2543-
+ compliant UAS will not generate such a response. If there is no
+ final response for the original request in 64*T1 seconds (T1 is
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 54]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ defined in Section 17.1.1.1), the client SHOULD then consider the
+ original transaction cancelled and SHOULD destroy the client
+ transaction handling the original request.
+
+9.2 Server Behavior
+
+ The CANCEL method requests that the TU at the server side cancel a
+ pending transaction. The TU determines the transaction to be
+ cancelled by taking the CANCEL request, and then assuming that the
+ request method is anything but CANCEL or ACK and applying the
+ transaction matching procedures of Section 17.2.3. The matching
+ transaction is the one to be cancelled.
+
+ The processing of a CANCEL request at a server depends on the type of
+ server. A stateless proxy will forward it, a stateful proxy might
+ respond to it and generate some CANCEL requests of its own, and a UAS
+ will respond to it. See Section 16.10 for proxy treatment of CANCEL.
+
+ A UAS first processes the CANCEL request according to the general UAS
+ processing described in Section 8.2. However, since CANCEL requests
+ are hop-by-hop and cannot be resubmitted, they cannot be challenged
+ by the server in order to get proper credentials in an Authorization
+ header field. Note also that CANCEL requests do not contain a
+ Require header field.
+
+ If the UAS did not find a matching transaction for the CANCEL
+ according to the procedure above, it SHOULD respond to the CANCEL
+ with a 481 (Call Leg/Transaction Does Not Exist). If the transaction
+ for the original request still exists, the behavior of the UAS on
+ receiving a CANCEL request depends on whether it has already sent a
+ final response for the original request. If it has, the CANCEL
+ request has no effect on the processing of the original request, no
+ effect on any session state, and no effect on the responses generated
+ for the original request. If the UAS has not issued a final response
+ for the original request, its behavior depends on the method of the
+ original request. If the original request was an INVITE, the UAS
+ SHOULD immediately respond to the INVITE with a 487 (Request
+ Terminated). A CANCEL request has no impact on the processing of
+ transactions with any other method defined in this specification.
+
+ Regardless of the method of the original request, as long as the
+ CANCEL matched an existing transaction, the UAS answers the CANCEL
+ request itself with a 200 (OK) response. This response is
+ constructed following the procedures described in Section 8.2.6
+ noting that the To tag of the response to the CANCEL and the To tag
+ in the response to the original request SHOULD be the same. The
+ response to CANCEL is passed to the server transaction for
+ transmission.
+
+
+
+Rosenberg, et. al. Standards Track [Page 55]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+10 Registrations
+
+10.1 Overview
+
+ SIP offers a discovery capability. If a user wants to initiate a
+ session with another user, SIP must discover the current host(s) at
+ which the destination user is reachable. This discovery process is
+ frequently accomplished by SIP network elements such as proxy servers
+ and redirect servers which are responsible for receiving a request,
+ determining where to send it based on knowledge of the location of
+ the user, and then sending it there. To do this, SIP network
+ elements consult an abstract service known as a location service,
+ which provides address bindings for a particular domain. These
+ address bindings map an incoming SIP or SIPS URI, sip:bob@biloxi.com,
+ for example, to one or more URIs that are somehow "closer" to the
+ desired user, sip:bob@engineering.biloxi.com, for example.
+ Ultimately, a proxy will consult a location service that maps a
+ received URI to the user agent(s) at which the desired recipient is
+ currently residing.
+
+ Registration creates bindings in a location service for a particular
+ domain that associates an address-of-record URI with one or more
+ contact addresses. Thus, when a proxy for that domain receives a
+ request whose Request-URI matches the address-of-record, the proxy
+ will forward the request to the contact addresses registered to that
+ address-of-record. Generally, it only makes sense to register an
+ address-of-record at a domain's location service when requests for
+ that address-of-record would be routed to that domain. In most
+ cases, this means that the domain of the registration will need to
+ match the domain in the URI of the address-of-record.
+
+ There are many ways by which the contents of the location service can
+ be established. One way is administratively. In the above example,
+ Bob is known to be a member of the engineering department through
+ access to a corporate database. However, SIP provides a mechanism
+ for a UA to create a binding explicitly. This mechanism is known as
+ registration.
+
+ Registration entails sending a REGISTER request to a special type of
+ UAS known as a registrar. A registrar acts as the front end to the
+ location service for a domain, reading and writing mappings based on
+ the contents of REGISTER requests. This location service is then
+ typically consulted by a proxy server that is responsible for routing
+ requests for that domain.
+
+ An illustration of the overall registration process is given in
+ Figure 2. Note that the registrar and proxy server are logical roles
+ that can be played by a single device in a network; for purposes of
+
+
+
+Rosenberg, et. al. Standards Track [Page 56]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ clarity the two are separated in this illustration. Also note that
+ UAs may send requests through a proxy server in order to reach a
+ registrar if the two are separate elements.
+
+ SIP does not mandate a particular mechanism for implementing the
+ location service. The only requirement is that a registrar for some
+ domain MUST be able to read and write data to the location service,
+ and a proxy or a redirect server for that domain MUST be capable of
+ reading that same data. A registrar MAY be co-located with a
+ particular SIP proxy server for the same domain.
+
+10.2 Constructing the REGISTER Request
+
+ REGISTER requests add, remove, and query bindings. A REGISTER
+ request can add a new binding between an address-of-record and one or
+ more contact addresses. Registration on behalf of a particular
+ address-of-record can be performed by a suitably authorized third
+ party. A client can also remove previous bindings or query to
+ determine which bindings are currently in place for an address-of-
+ record.
+
+ Except as noted, the construction of the REGISTER request and the
+ behavior of clients sending a REGISTER request is identical to the
+ general UAC behavior described in Section 8.1 and Section 17.1.
+
+ A REGISTER request does not establish a dialog. A UAC MAY include a
+ Route header field in a REGISTER request based on a pre-existing
+ route set as described in Section 8.1. The Record-Route header field
+ has no meaning in REGISTER requests or responses, and MUST be ignored
+ if present. In particular, the UAC MUST NOT create a new route set
+ based on the presence or absence of a Record-Route header field in
+ any response to a REGISTER request.
+
+ The following header fields, except Contact, MUST be included in a
+ REGISTER request. A Contact header field MAY be included:
+
+ Request-URI: The Request-URI names the domain of the location
+ service for which the registration is meant (for example,
+ "sip:chicago.com"). The "userinfo" and "@" components of the
+ SIP URI MUST NOT be present.
+
+ To: The To header field contains the address of record whose
+ registration is to be created, queried, or modified. The To
+ header field and the Request-URI field typically differ, as
+ the former contains a user name. This address-of-record MUST
+ be a SIP URI or SIPS URI.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 57]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ From: The From header field contains the address-of-record of the
+ person responsible for the registration. The value is the
+ same as the To header field unless the request is a third-
+ party registration.
+
+ Call-ID: All registrations from a UAC SHOULD use the same Call-ID
+ header field value for registrations sent to a particular
+ registrar.
+
+ If the same client were to use different Call-ID values, a
+ registrar could not detect whether a delayed REGISTER request
+ might have arrived out of order.
+
+ CSeq: The CSeq value guarantees proper ordering of REGISTER
+ requests. A UA MUST increment the CSeq value by one for each
+ REGISTER request with the same Call-ID.
+
+ Contact: REGISTER requests MAY contain a Contact header field with
+ zero or more values containing address bindings.
+
+ UAs MUST NOT send a new registration (that is, containing new Contact
+ header field values, as opposed to a retransmission) until they have
+ received a final response from the registrar for the previous one or
+ the previous REGISTER request has timed out.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 58]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ bob
+ +----+
+ | UA |
+ | |
+ +----+
+ |
+ |3)INVITE
+ | carol@chicago.com
+ chicago.com +--------+ V
+ +---------+ 2)Store|Location|4)Query +-----+
+ |Registrar|=======>| Service|<=======|Proxy|sip.chicago.com
+ +---------+ +--------+=======>+-----+
+ A 5)Resp |
+ | |
+ | |
+ 1)REGISTER| |
+ | |
+ +----+ |
+ | UA |<-------------------------------+
+ cube2214a| | 6)INVITE
+ +----+ carol@cube2214a.chicago.com
+ carol
+
+ Figure 2: REGISTER example
+
+ The following Contact header parameters have a special meaning in
+ REGISTER requests:
+
+ action: The "action" parameter from RFC 2543 has been deprecated.
+ UACs SHOULD NOT use the "action" parameter.
+
+ expires: The "expires" parameter indicates how long the UA would
+ like the binding to be valid. The value is a number
+ indicating seconds. If this parameter is not provided, the
+ value of the Expires header field is used instead.
+ Implementations MAY treat values larger than 2**32-1
+ (4294967295 seconds or 136 years) as equivalent to 2**32-1.
+ Malformed values SHOULD be treated as equivalent to 3600.
+
+10.2.1 Adding Bindings
+
+ The REGISTER request sent to a registrar includes the contact
+ address(es) to which SIP requests for the address-of-record should be
+ forwarded. The address-of-record is included in the To header field
+ of the REGISTER request.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 59]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The Contact header field values of the request typically consist of
+ SIP or SIPS URIs that identify particular SIP endpoints (for example,
+ "sip:carol@cube2214a.chicago.com"), but they MAY use any URI scheme.
+ A SIP UA can choose to register telephone numbers (with the tel URL,
+ RFC 2806 [9]) or email addresses (with a mailto URL, RFC 2368 [32])
+ as Contacts for an address-of-record, for example.
+
+ For example, Carol, with address-of-record "sip:carol@chicago.com",
+ would register with the SIP registrar of the domain chicago.com. Her
+ registrations would then be used by a proxy server in the chicago.com
+ domain to route requests for Carol's address-of-record to her SIP
+ endpoint.
+
+ Once a client has established bindings at a registrar, it MAY send
+ subsequent registrations containing new bindings or modifications to
+ existing bindings as necessary. The 2xx response to the REGISTER
+ request will contain, in a Contact header field, a complete list of
+ bindings that have been registered for this address-of-record at this
+ registrar.
+
+ If the address-of-record in the To header field of a REGISTER request
+ is a SIPS URI, then any Contact header field values in the request
+ SHOULD also be SIPS URIs. Clients should only register non-SIPS URIs
+ under a SIPS address-of-record when the security of the resource
+ represented by the contact address is guaranteed by other means.
+ This may be applicable to URIs that invoke protocols other than SIP,
+ or SIP devices secured by protocols other than TLS.
+
+ Registrations do not need to update all bindings. Typically, a UA
+ only updates its own contact addresses.
+
+10.2.1.1 Setting the Expiration Interval of Contact Addresses
+
+ When a client sends a REGISTER request, it MAY suggest an expiration
+ interval that indicates how long the client would like the
+ registration to be valid. (As described in Section 10.3, the
+ registrar selects the actual time interval based on its local
+ policy.)
+
+ There are two ways in which a client can suggest an expiration
+ interval for a binding: through an Expires header field or an
+ "expires" Contact header parameter. The latter allows expiration
+ intervals to be suggested on a per-binding basis when more than one
+ binding is given in a single REGISTER request, whereas the former
+ suggests an expiration interval for all Contact header field values
+ that do not contain the "expires" parameter.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 60]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ If neither mechanism for expressing a suggested expiration time is
+ present in a REGISTER, the client is indicating its desire for the
+ server to choose.
+
+10.2.1.2 Preferences among Contact Addresses
+
+ If more than one Contact is sent in a REGISTER request, the
+ registering UA intends to associate all of the URIs in these Contact
+ header field values with the address-of-record present in the To
+ field. This list can be prioritized with the "q" parameter in the
+ Contact header field. The "q" parameter indicates a relative
+ preference for the particular Contact header field value compared to
+ other bindings for this address-of-record. Section 16.6 describes
+ how a proxy server uses this preference indication.
+
+10.2.2 Removing Bindings
+
+ Registrations are soft state and expire unless refreshed, but can
+ also be explicitly removed. A client can attempt to influence the
+ expiration interval selected by the registrar as described in Section
+ 10.2.1. A UA requests the immediate removal of a binding by
+ specifying an expiration interval of "0" for that contact address in
+ a REGISTER request. UAs SHOULD support this mechanism so that
+ bindings can be removed before their expiration interval has passed.
+
+ The REGISTER-specific Contact header field value of "*" applies to
+ all registrations, but it MUST NOT be used unless the Expires header
+ field is present with a value of "0".
+
+ Use of the "*" Contact header field value allows a registering UA
+ to remove all bindings associated with an address-of-record
+ without knowing their precise values.
+
+10.2.3 Fetching Bindings
+
+ A success response to any REGISTER request contains the complete list
+ of existing bindings, regardless of whether the request contained a
+ Contact header field. If no Contact header field is present in a
+ REGISTER request, the list of bindings is left unchanged.
+
+10.2.4 Refreshing Bindings
+
+ Each UA is responsible for refreshing the bindings that it has
+ previously established. A UA SHOULD NOT refresh bindings set up by
+ other UAs.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 61]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The 200 (OK) response from the registrar contains a list of Contact
+ fields enumerating all current bindings. The UA compares each
+ contact address to see if it created the contact address, using
+ comparison rules in Section 19.1.4. If so, it updates the expiration
+ time interval according to the expires parameter or, if absent, the
+ Expires field value. The UA then issues a REGISTER request for each
+ of its bindings before the expiration interval has elapsed. It MAY
+ combine several updates into one REGISTER request.
+
+ A UA SHOULD use the same Call-ID for all registrations during a
+ single boot cycle. Registration refreshes SHOULD be sent to the same
+ network address as the original registration, unless redirected.
+
+10.2.5 Setting the Internal Clock
+
+ If the response for a REGISTER request contains a Date header field,
+ the client MAY use this header field to learn the current time in
+ order to set any internal clocks.
+
+10.2.6 Discovering a Registrar
+
+ UAs can use three ways to determine the address to which to send
+ registrations: by configuration, using the address-of-record, and
+ multicast. A UA can be configured, in ways beyond the scope of this
+ specification, with a registrar address. If there is no configured
+ registrar address, the UA SHOULD use the host part of the address-
+ of-record as the Request-URI and address the request there, using the
+ normal SIP server location mechanisms [4]. For example, the UA for
+ the user "sip:carol@chicago.com" addresses the REGISTER request to
+ "sip:chicago.com".
+
+ Finally, a UA can be configured to use multicast. Multicast
+ registrations are addressed to the well-known "all SIP servers"
+ multicast address "sip.mcast.net" (224.0.1.75 for IPv4). No well-
+ known IPv6 multicast address has been allocated; such an allocation
+ will be documented separately when needed. SIP UAs MAY listen to
+ that address and use it to become aware of the location of other
+ local users (see [33]); however, they do not respond to the request.
+
+ Multicast registration may be inappropriate in some environments,
+ for example, if multiple businesses share the same local area
+ network.
+
+10.2.7 Transmitting a Request
+
+ Once the REGISTER method has been constructed, and the destination of
+ the message identified, UACs follow the procedures described in
+ Section 8.1.2 to hand off the REGISTER to the transaction layer.
+
+
+
+Rosenberg, et. al. Standards Track [Page 62]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ If the transaction layer returns a timeout error because the REGISTER
+ yielded no response, the UAC SHOULD NOT immediately re-attempt a
+ registration to the same registrar.
+
+ An immediate re-attempt is likely to also timeout. Waiting some
+ reasonable time interval for the conditions causing the timeout to
+ be corrected reduces unnecessary load on the network. No specific
+ interval is mandated.
+
+10.2.8 Error Responses
+
+ If a UA receives a 423 (Interval Too Brief) response, it MAY retry
+ the registration after making the expiration interval of all contact
+ addresses in the REGISTER request equal to or greater than the
+ expiration interval within the Min-Expires header field of the 423
+ (Interval Too Brief) response.
+
+10.3 Processing REGISTER Requests
+
+ A registrar is a UAS that responds to REGISTER requests and maintains
+ a list of bindings that are accessible to proxy servers and redirect
+ servers within its administrative domain. A registrar handles
+ requests according to Section 8.2 and Section 17.2, but it accepts
+ only REGISTER requests. A registrar MUST not generate 6xx responses.
+
+ A registrar MAY redirect REGISTER requests as appropriate. One
+ common usage would be for a registrar listening on a multicast
+ interface to redirect multicast REGISTER requests to its own unicast
+ interface with a 302 (Moved Temporarily) response.
+
+ Registrars MUST ignore the Record-Route header field if it is
+ included in a REGISTER request. Registrars MUST NOT include a
+ Record-Route header field in any response to a REGISTER request.
+
+ A registrar might receive a request that traversed a proxy which
+ treats REGISTER as an unknown request and which added a Record-
+ Route header field value.
+
+ A registrar has to know (for example, through configuration) the set
+ of domain(s) for which it maintains bindings. REGISTER requests MUST
+ be processed by a registrar in the order that they are received.
+ REGISTER requests MUST also be processed atomically, meaning that a
+ particular REGISTER request is either processed completely or not at
+ all. Each REGISTER message MUST be processed independently of any
+ other registration or binding changes.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 63]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ When receiving a REGISTER request, a registrar follows these steps:
+
+ 1. The registrar inspects the Request-URI to determine whether it
+ has access to bindings for the domain identified in the
+ Request-URI. If not, and if the server also acts as a proxy
+ server, the server SHOULD forward the request to the addressed
+ domain, following the general behavior for proxying messages
+ described in Section 16.
+
+ 2. To guarantee that the registrar supports any necessary
+ extensions, the registrar MUST process the Require header field
+ values as described for UASs in Section 8.2.2.
+
+ 3. A registrar SHOULD authenticate the UAC. Mechanisms for the
+ authentication of SIP user agents are described in Section 22.
+ Registration behavior in no way overrides the generic
+ authentication framework for SIP. If no authentication
+ mechanism is available, the registrar MAY take the From address
+ as the asserted identity of the originator of the request.
+
+ 4. The registrar SHOULD determine if the authenticated user is
+ authorized to modify registrations for this address-of-record.
+ For example, a registrar might consult an authorization
+ database that maps user names to a list of addresses-of-record
+ for which that user has authorization to modify bindings. If
+ the authenticated user is not authorized to modify bindings,
+ the registrar MUST return a 403 (Forbidden) and skip the
+ remaining steps.
+
+ In architectures that support third-party registration, one
+ entity may be responsible for updating the registrations
+ associated with multiple addresses-of-record.
+
+ 5. The registrar extracts the address-of-record from the To header
+ field of the request. If the address-of-record is not valid
+ for the domain in the Request-URI, the registrar MUST send a
+ 404 (Not Found) response and skip the remaining steps. The URI
+ MUST then be converted to a canonical form. To do that, all
+ URI parameters MUST be removed (including the user-param), and
+ any escaped characters MUST be converted to their unescaped
+ form. The result serves as an index into the list of bindings.
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 64]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 6. The registrar checks whether the request contains the Contact
+ header field. If not, it skips to the last step. If the
+ Contact header field is present, the registrar checks if there
+ is one Contact field value that contains the special value "*"
+ and an Expires field. If the request has additional Contact
+ fields or an expiration time other than zero, the request is
+ invalid, and the server MUST return a 400 (Invalid Request) and
+ skip the remaining steps. If not, the registrar checks whether
+ the Call-ID agrees with the value stored for each binding. If
+ not, it MUST remove the binding. If it does agree, it MUST
+ remove the binding only if the CSeq in the request is higher
+ than the value stored for that binding. Otherwise, the update
+ MUST be aborted and the request fails.
+
+ 7. The registrar now processes each contact address in the Contact
+ header field in turn. For each address, it determines the
+ expiration interval as follows:
+
+ - If the field value has an "expires" parameter, that value
+ MUST be taken as the requested expiration.
+
+ - If there is no such parameter, but the request has an
+ Expires header field, that value MUST be taken as the
+ requested expiration.
+
+ - If there is neither, a locally-configured default value MUST
+ be taken as the requested expiration.
+
+ The registrar MAY choose an expiration less than the requested
+ expiration interval. If and only if the requested expiration
+ interval is greater than zero AND smaller than one hour AND
+ less than a registrar-configured minimum, the registrar MAY
+ reject the registration with a response of 423 (Interval Too
+ Brief). This response MUST contain a Min-Expires header field
+ that states the minimum expiration interval the registrar is
+ willing to honor. It then skips the remaining steps.
+
+ Allowing the registrar to set the registration interval
+ protects it against excessively frequent registration refreshes
+ while limiting the state that it needs to maintain and
+ decreasing the likelihood of registrations going stale. The
+ expiration interval of a registration is frequently used in the
+ creation of services. An example is a follow-me service, where
+ the user may only be available at a terminal for a brief
+ period. Therefore, registrars should accept brief
+ registrations; a request should only be rejected if the
+ interval is so short that the refreshes would degrade registrar
+ performance.
+
+
+
+Rosenberg, et. al. Standards Track [Page 65]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ For each address, the registrar then searches the list of
+ current bindings using the URI comparison rules. If the
+ binding does not exist, it is tentatively added. If the
+ binding does exist, the registrar checks the Call-ID value. If
+ the Call-ID value in the existing binding differs from the
+ Call-ID value in the request, the binding MUST be removed if
+ the expiration time is zero and updated otherwise. If they are
+ the same, the registrar compares the CSeq value. If the value
+ is higher than that of the existing binding, it MUST update or
+ remove the binding as above. If not, the update MUST be
+ aborted and the request fails.
+
+ This algorithm ensures that out-of-order requests from the same
+ UA are ignored.
+
+ Each binding record records the Call-ID and CSeq values from
+ the request.
+
+ The binding updates MUST be committed (that is, made visible to
+ the proxy or redirect server) if and only if all binding
+ updates and additions succeed. If any one of them fails (for
+ example, because the back-end database commit failed), the
+ request MUST fail with a 500 (Server Error) response and all
+ tentative binding updates MUST be removed.
+
+ 8. The registrar returns a 200 (OK) response. The response MUST
+ contain Contact header field values enumerating all current
+ bindings. Each Contact value MUST feature an "expires"
+ parameter indicating its expiration interval chosen by the
+ registrar. The response SHOULD include a Date header field.
+
+11 Querying for Capabilities
+
+ The SIP method OPTIONS allows a UA to query another UA or a proxy
+ server as to its capabilities. This allows a client to discover
+ information about the supported methods, content types, extensions,
+ codecs, etc. without "ringing" the other party. For example, before
+ a client inserts a Require header field into an INVITE listing an
+ option that it is not certain the destination UAS supports, the
+ client can query the destination UAS with an OPTIONS to see if this
+ option is returned in a Supported header field. All UAs MUST support
+ the OPTIONS method.
+
+ The target of the OPTIONS request is identified by the Request-URI,
+ which could identify another UA or a SIP server. If the OPTIONS is
+ addressed to a proxy server, the Request-URI is set without a user
+ part, similar to the way a Request-URI is set for a REGISTER request.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 66]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Alternatively, a server receiving an OPTIONS request with a Max-
+ Forwards header field value of 0 MAY respond to the request
+ regardless of the Request-URI.
+
+ This behavior is common with HTTP/1.1. This behavior can be used
+ as a "traceroute" functionality to check the capabilities of
+ individual hop servers by sending a series of OPTIONS requests
+ with incremented Max-Forwards values.
+
+ As is the case for general UA behavior, the transaction layer can
+ return a timeout error if the OPTIONS yields no response. This may
+ indicate that the target is unreachable and hence unavailable.
+
+ An OPTIONS request MAY be sent as part of an established dialog to
+ query the peer on capabilities that may be utilized later in the
+ dialog.
+
+11.1 Construction of OPTIONS Request
+
+ An OPTIONS request is constructed using the standard rules for a SIP
+ request as discussed in Section 8.1.1.
+
+ A Contact header field MAY be present in an OPTIONS.
+
+ An Accept header field SHOULD be included to indicate the type of
+ message body the UAC wishes to receive in the response. Typically,
+ this is set to a format that is used to describe the media
+ capabilities of a UA, such as SDP (application/sdp).
+
+ The response to an OPTIONS request is assumed to be scoped to the
+ Request-URI in the original request. However, only when an OPTIONS
+ is sent as part of an established dialog is it guaranteed that future
+ requests will be received by the server that generated the OPTIONS
+ response.
+
+ Example OPTIONS request:
+
+ OPTIONS sip:carol@chicago.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877
+ Max-Forwards: 70
+ To: <sip:carol@chicago.com>
+ From: Alice <sip:alice@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710
+ CSeq: 63104 OPTIONS
+ Contact: <sip:alice@pc33.atlanta.com>
+ Accept: application/sdp
+ Content-Length: 0
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 67]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+11.2 Processing of OPTIONS Request
+
+ The response to an OPTIONS is constructed using the standard rules
+ for a SIP response as discussed in Section 8.2.6. The response code
+ chosen MUST be the same that would have been chosen had the request
+ been an INVITE. That is, a 200 (OK) would be returned if the UAS is
+ ready to accept a call, a 486 (Busy Here) would be returned if the
+ UAS is busy, etc. This allows an OPTIONS request to be used to
+ determine the basic state of a UAS, which can be an indication of
+ whether the UAS will accept an INVITE request.
+
+ An OPTIONS request received within a dialog generates a 200 (OK)
+ response that is identical to one constructed outside a dialog and
+ does not have any impact on the dialog.
+
+ This use of OPTIONS has limitations due to the differences in proxy
+ handling of OPTIONS and INVITE requests. While a forked INVITE can
+ result in multiple 200 (OK) responses being returned, a forked
+ OPTIONS will only result in a single 200 (OK) response, since it is
+ treated by proxies using the non-INVITE handling. See Section 16.7
+ for the normative details.
+
+ If the response to an OPTIONS is generated by a proxy server, the
+ proxy returns a 200 (OK), listing the capabilities of the server.
+ The response does not contain a message body.
+
+ Allow, Accept, Accept-Encoding, Accept-Language, and Supported header
+ fields SHOULD be present in a 200 (OK) response to an OPTIONS
+ request. If the response is generated by a proxy, the Allow header
+ field SHOULD be omitted as it is ambiguous since a proxy is method
+ agnostic. Contact header fields MAY be present in a 200 (OK)
+ response and have the same semantics as in a 3xx response. That is,
+ they may list a set of alternative names and methods of reaching the
+ user. A Warning header field MAY be present.
+
+ A message body MAY be sent, the type of which is determined by the
+ Accept header field in the OPTIONS request (application/sdp is the
+ default if the Accept header field is not present). If the types
+ include one that can describe media capabilities, the UAS SHOULD
+ include a body in the response for that purpose. Details on the
+ construction of such a body in the case of application/sdp are
+ described in [13].
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 68]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Example OPTIONS response generated by a UAS (corresponding to the
+ request in Section 11.1):
+
+ SIP/2.0 200 OK
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877
+ ;received=192.0.2.4
+ To: <sip:carol@chicago.com>;tag=93810874
+ From: Alice <sip:alice@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710
+ CSeq: 63104 OPTIONS
+ Contact: <sip:carol@chicago.com>
+ Contact: <mailto:carol@chicago.com>
+ Allow: INVITE, ACK, CANCEL, OPTIONS, BYE
+ Accept: application/sdp
+ Accept-Encoding: gzip
+ Accept-Language: en
+ Supported: foo
+ Content-Type: application/sdp
+ Content-Length: 274
+
+ (SDP not shown)
+
+12 Dialogs
+
+ A key concept for a user agent is that of a dialog. A dialog
+ represents a peer-to-peer SIP relationship between two user agents
+ that persists for some time. The dialog facilitates sequencing of
+ messages between the user agents and proper routing of requests
+ between both of them. The dialog represents a context in which to
+ interpret SIP messages. Section 8 discussed method independent UA
+ processing for requests and responses outside of a dialog. This
+ section discusses how those requests and responses are used to
+ construct a dialog, and then how subsequent requests and responses
+ are sent within a dialog.
+
+ A dialog is identified at each UA with a dialog ID, which consists of
+ a Call-ID value, a local tag and a remote tag. The dialog ID at each
+ UA involved in the dialog is not the same. Specifically, the local
+ tag at one UA is identical to the remote tag at the peer UA. The
+ tags are opaque tokens that facilitate the generation of unique
+ dialog IDs.
+
+ A dialog ID is also associated with all responses and with any
+ request that contains a tag in the To field. The rules for computing
+ the dialog ID of a message depend on whether the SIP element is a UAC
+ or UAS. For a UAC, the Call-ID value of the dialog ID is set to the
+ Call-ID of the message, the remote tag is set to the tag in the To
+ field of the message, and the local tag is set to the tag in the From
+
+
+
+Rosenberg, et. al. Standards Track [Page 69]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ field of the message (these rules apply to both requests and
+ responses). As one would expect for a UAS, the Call-ID value of the
+ dialog ID is set to the Call-ID of the message, the remote tag is set
+ to the tag in the From field of the message, and the local tag is set
+ to the tag in the To field of the message.
+
+ A dialog contains certain pieces of state needed for further message
+ transmissions within the dialog. This state consists of the dialog
+ ID, a local sequence number (used to order requests from the UA to
+ its peer), a remote sequence number (used to order requests from its
+ peer to the UA), a local URI, a remote URI, remote target, a boolean
+ flag called "secure", and a route set, which is an ordered list of
+ URIs. The route set is the list of servers that need to be traversed
+ to send a request to the peer. A dialog can also be in the "early"
+ state, which occurs when it is created with a provisional response,
+ and then transition to the "confirmed" state when a 2xx final
+ response arrives. For other responses, or if no response arrives at
+ all on that dialog, the early dialog terminates.
+
+12.1 Creation of a Dialog
+
+ Dialogs are created through the generation of non-failure responses
+ to requests with specific methods. Within this specification, only
+ 2xx and 101-199 responses with a To tag, where the request was
+ INVITE, will establish a dialog. A dialog established by a non-final
+ response to a request is in the "early" state and it is called an
+ early dialog. Extensions MAY define other means for creating
+ dialogs. Section 13 gives more details that are specific to the
+ INVITE method. Here, we describe the process for creation of dialog
+ state that is not dependent on the method.
+
+ UAs MUST assign values to the dialog ID components as described
+ below.
+
+12.1.1 UAS behavior
+
+ When a UAS responds to a request with a response that establishes a
+ dialog (such as a 2xx to INVITE), the UAS MUST copy all Record-Route
+ header field values from the request into the response (including the
+ URIs, URI parameters, and any Record-Route header field parameters,
+ whether they are known or unknown to the UAS) and MUST maintain the
+ order of those values. The UAS MUST add a Contact header field to
+ the response. The Contact header field contains an address where the
+ UAS would like to be contacted for subsequent requests in the dialog
+ (which includes the ACK for a 2xx response in the case of an INVITE).
+ Generally, the host portion of this URI is the IP address or FQDN of
+ the host. The URI provided in the Contact header field MUST be a SIP
+ or SIPS URI. If the request that initiated the dialog contained a
+
+
+
+Rosenberg, et. al. Standards Track [Page 70]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ SIPS URI in the Request-URI or in the top Record-Route header field
+ value, if there was any, or the Contact header field if there was no
+ Record-Route header field, the Contact header field in the response
+ MUST be a SIPS URI. The URI SHOULD have global scope (that is, the
+ same URI can be used in messages outside this dialog). The same way,
+ the scope of the URI in the Contact header field of the INVITE is not
+ limited to this dialog either. It can therefore be used in messages
+ to the UAC even outside this dialog.
+
+ The UAS then constructs the state of the dialog. This state MUST be
+ maintained for the duration of the dialog.
+
+ If the request arrived over TLS, and the Request-URI contained a SIPS
+ URI, the "secure" flag is set to TRUE.
+
+ The route set MUST be set to the list of URIs in the Record-Route
+ header field from the request, taken in order and preserving all URI
+ parameters. If no Record-Route header field is present in the
+ request, the route set MUST be set to the empty set. This route set,
+ even if empty, overrides any pre-existing route set for future
+ requests in this dialog. The remote target MUST be set to the URI
+ from the Contact header field of the request.
+
+ The remote sequence number MUST be set to the value of the sequence
+ number in the CSeq header field of the request. The local sequence
+ number MUST be empty. The call identifier component of the dialog ID
+ MUST be set to the value of the Call-ID in the request. The local
+ tag component of the dialog ID MUST be set to the tag in the To field
+ in the response to the request (which always includes a tag), and the
+ remote tag component of the dialog ID MUST be set to the tag from the
+ From field in the request. A UAS MUST be prepared to receive a
+ request without a tag in the From field, in which case the tag is
+ considered to have a value of null.
+
+ This is to maintain backwards compatibility with RFC 2543, which
+ did not mandate From tags.
+
+ The remote URI MUST be set to the URI in the From field, and the
+ local URI MUST be set to the URI in the To field.
+
+12.1.2 UAC Behavior
+
+ When a UAC sends a request that can establish a dialog (such as an
+ INVITE) it MUST provide a SIP or SIPS URI with global scope (i.e.,
+ the same SIP URI can be used in messages outside this dialog) in the
+ Contact header field of the request. If the request has a Request-
+ URI or a topmost Route header field value with a SIPS URI, the
+ Contact header field MUST contain a SIPS URI.
+
+
+
+Rosenberg, et. al. Standards Track [Page 71]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ When a UAC receives a response that establishes a dialog, it
+ constructs the state of the dialog. This state MUST be maintained
+ for the duration of the dialog.
+
+ If the request was sent over TLS, and the Request-URI contained a
+ SIPS URI, the "secure" flag is set to TRUE.
+
+ The route set MUST be set to the list of URIs in the Record-Route
+ header field from the response, taken in reverse order and preserving
+ all URI parameters. If no Record-Route header field is present in
+ the response, the route set MUST be set to the empty set. This route
+ set, even if empty, overrides any pre-existing route set for future
+ requests in this dialog. The remote target MUST be set to the URI
+ from the Contact header field of the response.
+
+ The local sequence number MUST be set to the value of the sequence
+ number in the CSeq header field of the request. The remote sequence
+ number MUST be empty (it is established when the remote UA sends a
+ request within the dialog). The call identifier component of the
+ dialog ID MUST be set to the value of the Call-ID in the request.
+ The local tag component of the dialog ID MUST be set to the tag in
+ the From field in the request, and the remote tag component of the
+ dialog ID MUST be set to the tag in the To field of the response. A
+ UAC MUST be prepared to receive a response without a tag in the To
+ field, in which case the tag is considered to have a value of null.
+
+ This is to maintain backwards compatibility with RFC 2543, which
+ did not mandate To tags.
+
+ The remote URI MUST be set to the URI in the To field, and the local
+ URI MUST be set to the URI in the From field.
+
+12.2 Requests within a Dialog
+
+ Once a dialog has been established between two UAs, either of them
+ MAY initiate new transactions as needed within the dialog. The UA
+ sending the request will take the UAC role for the transaction. The
+ UA receiving the request will take the UAS role. Note that these may
+ be different roles than the UAs held during the transaction that
+ established the dialog.
+
+ Requests within a dialog MAY contain Record-Route and Contact header
+ fields. However, these requests do not cause the dialog's route set
+ to be modified, although they may modify the remote target URI.
+ Specifically, requests that are not target refresh requests do not
+ modify the dialog's remote target URI, and requests that are target
+ refresh requests do. For dialogs that have been established with an
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 72]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ INVITE, the only target refresh request defined is re-INVITE (see
+ Section 14). Other extensions may define different target refresh
+ requests for dialogs established in other ways.
+
+ Note that an ACK is NOT a target refresh request.
+
+ Target refresh requests only update the dialog's remote target URI,
+ and not the route set formed from the Record-Route. Updating the
+ latter would introduce severe backwards compatibility problems with
+ RFC 2543-compliant systems.
+
+12.2.1 UAC Behavior
+
+12.2.1.1 Generating the Request
+
+ A request within a dialog is constructed by using many of the
+ components of the state stored as part of the dialog.
+
+ The URI in the To field of the request MUST be set to the remote URI
+ from the dialog state. The tag in the To header field of the request
+ MUST be set to the remote tag of the dialog ID. The From URI of the
+ request MUST be set to the local URI from the dialog state. The tag
+ in the From header field of the request MUST be set to the local tag
+ of the dialog ID. If the value of the remote or local tags is null,
+ the tag parameter MUST be omitted from the To or From header fields,
+ respectively.
+
+ Usage of the URI from the To and From fields in the original
+ request within subsequent requests is done for backwards
+ compatibility with RFC 2543, which used the URI for dialog
+ identification. In this specification, only the tags are used for
+ dialog identification. It is expected that mandatory reflection
+ of the original To and From URI in mid-dialog requests will be
+ deprecated in a subsequent revision of this specification.
+
+ The Call-ID of the request MUST be set to the Call-ID of the dialog.
+ Requests within a dialog MUST contain strictly monotonically
+ increasing and contiguous CSeq sequence numbers (increasing-by-one)
+ in each direction (excepting ACK and CANCEL of course, whose numbers
+ equal the requests being acknowledged or cancelled). Therefore, if
+ the local sequence number is not empty, the value of the local
+ sequence number MUST be incremented by one, and this value MUST be
+ placed into the CSeq header field. If the local sequence number is
+ empty, an initial value MUST be chosen using the guidelines of
+ Section 8.1.1.5. The method field in the CSeq header field value
+ MUST match the method of the request.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 73]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ With a length of 32 bits, a client could generate, within a single
+ call, one request a second for about 136 years before needing to
+ wrap around. The initial value of the sequence number is chosen
+ so that subsequent requests within the same call will not wrap
+ around. A non-zero initial value allows clients to use a time-
+ based initial sequence number. A client could, for example,
+ choose the 31 most significant bits of a 32-bit second clock as an
+ initial sequence number.
+
+ The UAC uses the remote target and route set to build the Request-URI
+ and Route header field of the request.
+
+ If the route set is empty, the UAC MUST place the remote target URI
+ into the Request-URI. The UAC MUST NOT add a Route header field to
+ the request.
+
+ If the route set is not empty, and the first URI in the route set
+ contains the lr parameter (see Section 19.1.1), the UAC MUST place
+ the remote target URI into the Request-URI and MUST include a Route
+ header field containing the route set values in order, including all
+ parameters.
+
+ If the route set is not empty, and its first URI does not contain the
+ lr parameter, the UAC MUST place the first URI from the route set
+ into the Request-URI, stripping any parameters that are not allowed
+ in a Request-URI. The UAC MUST add a Route header field containing
+ the remainder of the route set values in order, including all
+ parameters. The UAC MUST then place the remote target URI into the
+ Route header field as the last value.
+
+ For example, if the remote target is sip:user@remoteua and the route
+ set contains:
+
+ <sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>
+
+ The request will be formed with the following Request-URI and Route
+ header field:
+
+ METHOD sip:proxy1
+ Route: <sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>,<sip:user@remoteua>
+
+ If the first URI of the route set does not contain the lr
+ parameter, the proxy indicated does not understand the routing
+ mechanisms described in this document and will act as specified in
+ RFC 2543, replacing the Request-URI with the first Route header
+ field value it receives while forwarding the message. Placing the
+ Request-URI at the end of the Route header field preserves the
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 74]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ information in that Request-URI across the strict router (it will
+ be returned to the Request-URI when the request reaches a loose-
+ router).
+
+ A UAC SHOULD include a Contact header field in any target refresh
+ requests within a dialog, and unless there is a need to change it,
+ the URI SHOULD be the same as used in previous requests within the
+ dialog. If the "secure" flag is true, that URI MUST be a SIPS URI.
+ As discussed in Section 12.2.2, a Contact header field in a target
+ refresh request updates the remote target URI. This allows a UA to
+ provide a new contact address, should its address change during the
+ duration of the dialog.
+
+ However, requests that are not target refresh requests do not affect
+ the remote target URI for the dialog.
+
+ The rest of the request is formed as described in Section 8.1.1.
+
+ Once the request has been constructed, the address of the server is
+ computed and the request is sent, using the same procedures for
+ requests outside of a dialog (Section 8.1.2).
+
+ The procedures in Section 8.1.2 will normally result in the
+ request being sent to the address indicated by the topmost Route
+ header field value or the Request-URI if no Route header field is
+ present. Subject to certain restrictions, they allow the request
+ to be sent to an alternate address (such as a default outbound
+ proxy not represented in the route set).
+
+12.2.1.2 Processing the Responses
+
+ The UAC will receive responses to the request from the transaction
+ layer. If the client transaction returns a timeout, this is treated
+ as a 408 (Request Timeout) response.
+
+ The behavior of a UAC that receives a 3xx response for a request sent
+ within a dialog is the same as if the request had been sent outside a
+ dialog. This behavior is described in Section 8.1.3.4.
+
+ Note, however, that when the UAC tries alternative locations, it
+ still uses the route set for the dialog to build the Route header
+ of the request.
+
+ When a UAC receives a 2xx response to a target refresh request, it
+ MUST replace the dialog's remote target URI with the URI from the
+ Contact header field in that response, if present.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 75]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ If the response for a request within a dialog is a 481
+ (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
+ SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
+ no response at all is received for the request (the client
+ transaction would inform the TU about the timeout.)
+
+ For INVITE initiated dialogs, terminating the dialog consists of
+ sending a BYE.
+
+12.2.2 UAS Behavior
+
+ Requests sent within a dialog, as any other requests, are atomic. If
+ a particular request is accepted by the UAS, all the state changes
+ associated with it are performed. If the request is rejected, none
+ of the state changes are performed.
+
+ Note that some requests, such as INVITEs, affect several pieces of
+ state.
+
+ The UAS will receive the request from the transaction layer. If the
+ request has a tag in the To header field, the UAS core computes the
+ dialog identifier corresponding to the request and compares it with
+ existing dialogs. If there is a match, this is a mid-dialog request.
+ In that case, the UAS first applies the same processing rules for
+ requests outside of a dialog, discussed in Section 8.2.
+
+ If the request has a tag in the To header field, but the dialog
+ identifier does not match any existing dialogs, the UAS may have
+ crashed and restarted, or it may have received a request for a
+ different (possibly failed) UAS (the UASs can construct the To tags
+ so that a UAS can identify that the tag was for a UAS for which it is
+ providing recovery). Another possibility is that the incoming
+ request has been simply misrouted. Based on the To tag, the UAS MAY
+ either accept or reject the request. Accepting the request for
+ acceptable To tags provides robustness, so that dialogs can persist
+ even through crashes. UAs wishing to support this capability must
+ take into consideration some issues such as choosing monotonically
+ increasing CSeq sequence numbers even across reboots, reconstructing
+ the route set, and accepting out-of-range RTP timestamps and sequence
+ numbers.
+
+ If the UAS wishes to reject the request because it does not wish to
+ recreate the dialog, it MUST respond to the request with a 481
+ (Call/Transaction Does Not Exist) status code and pass that to the
+ server transaction.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 76]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Requests that do not change in any way the state of a dialog may be
+ received within a dialog (for example, an OPTIONS request). They are
+ processed as if they had been received outside the dialog.
+
+ If the remote sequence number is empty, it MUST be set to the value
+ of the sequence number in the CSeq header field value in the request.
+ If the remote sequence number was not empty, but the sequence number
+ of the request is lower than the remote sequence number, the request
+ is out of order and MUST be rejected with a 500 (Server Internal
+ Error) response. If the remote sequence number was not empty, and
+ the sequence number of the request is greater than the remote
+ sequence number, the request is in order. It is possible for the
+ CSeq sequence number to be higher than the remote sequence number by
+ more than one. This is not an error condition, and a UAS SHOULD be
+ prepared to receive and process requests with CSeq values more than
+ one higher than the previous received request. The UAS MUST then set
+ the remote sequence number to the value of the sequence number in the
+ CSeq header field value in the request.
+
+ If a proxy challenges a request generated by the UAC, the UAC has
+ to resubmit the request with credentials. The resubmitted request
+ will have a new CSeq number. The UAS will never see the first
+ request, and thus, it will notice a gap in the CSeq number space.
+ Such a gap does not represent any error condition.
+
+ When a UAS receives a target refresh request, it MUST replace the
+ dialog's remote target URI with the URI from the Contact header field
+ in that request, if present.
+
+12.3 Termination of a Dialog
+
+ Independent of the method, if a request outside of a dialog generates
+ a non-2xx final response, any early dialogs created through
+ provisional responses to that request are terminated. The mechanism
+ for terminating confirmed dialogs is method specific. In this
+ specification, the BYE method terminates a session and the dialog
+ associated with it. See Section 15 for details.
+
+13 Initiating a Session
+
+13.1 Overview
+
+ When a user agent client desires to initiate a session (for example,
+ audio, video, or a game), it formulates an INVITE request. The
+ INVITE request asks a server to establish a session. This request
+ may be forwarded by proxies, eventually arriving at one or more UAS
+ that can potentially accept the invitation. These UASs will
+ frequently need to query the user about whether to accept the
+
+
+
+Rosenberg, et. al. Standards Track [Page 77]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ invitation. After some time, those UASs can accept the invitation
+ (meaning the session is to be established) by sending a 2xx response.
+ If the invitation is not accepted, a 3xx, 4xx, 5xx or 6xx response is
+ sent, depending on the reason for the rejection. Before sending a
+ final response, the UAS can also send provisional responses (1xx) to
+ advise the UAC of progress in contacting the called user.
+
+ After possibly receiving one or more provisional responses, the UAC
+ will get one or more 2xx responses or one non-2xx final response.
+ Because of the protracted amount of time it can take to receive final
+ responses to INVITE, the reliability mechanisms for INVITE
+ transactions differ from those of other requests (like OPTIONS).
+ Once it receives a final response, the UAC needs to send an ACK for
+ every final response it receives. The procedure for sending this ACK
+ depends on the type of response. For final responses between 300 and
+ 699, the ACK processing is done in the transaction layer and follows
+ one set of rules (See Section 17). For 2xx responses, the ACK is
+ generated by the UAC core.
+
+ A 2xx response to an INVITE establishes a session, and it also
+ creates a dialog between the UA that issued the INVITE and the UA
+ that generated the 2xx response. Therefore, when multiple 2xx
+ responses are received from different remote UAs (because the INVITE
+ forked), each 2xx establishes a different dialog. All these dialogs
+ are part of the same call.
+
+ This section provides details on the establishment of a session using
+ INVITE. A UA that supports INVITE MUST also support ACK, CANCEL and
+ BYE.
+
+13.2 UAC Processing
+
+13.2.1 Creating the Initial INVITE
+
+ Since the initial INVITE represents a request outside of a dialog,
+ its construction follows the procedures of Section 8.1.1. Additional
+ processing is required for the specific case of INVITE.
+
+ An Allow header field (Section 20.5) SHOULD be present in the INVITE.
+ It indicates what methods can be invoked within a dialog, on the UA
+ sending the INVITE, for the duration of the dialog. For example, a
+ UA capable of receiving INFO requests within a dialog [34] SHOULD
+ include an Allow header field listing the INFO method.
+
+ A Supported header field (Section 20.37) SHOULD be present in the
+ INVITE. It enumerates all the extensions understood by the UAC.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 78]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ An Accept (Section 20.1) header field MAY be present in the INVITE.
+ It indicates which Content-Types are acceptable to the UA, in both
+ the response received by it, and in any subsequent requests sent to
+ it within dialogs established by the INVITE. The Accept header field
+ is especially useful for indicating support of various session
+ description formats.
+
+ The UAC MAY add an Expires header field (Section 20.19) to limit the
+ validity of the invitation. If the time indicated in the Expires
+ header field is reached and no final answer for the INVITE has been
+ received, the UAC core SHOULD generate a CANCEL request for the
+ INVITE, as per Section 9.
+
+ A UAC MAY also find it useful to add, among others, Subject (Section
+ 20.36), Organization (Section 20.25) and User-Agent (Section 20.41)
+ header fields. They all contain information related to the INVITE.
+
+ The UAC MAY choose to add a message body to the INVITE. Section
+ 8.1.1.10 deals with how to construct the header fields -- Content-
+ Type among others -- needed to describe the message body.
+
+ There are special rules for message bodies that contain a session
+ description - their corresponding Content-Disposition is "session".
+ SIP uses an offer/answer model where one UA sends a session
+ description, called the offer, which contains a proposed description
+ of the session. The offer indicates the desired communications means
+ (audio, video, games), parameters of those means (such as codec
+ types) and addresses for receiving media from the answerer. The
+ other UA responds with another session description, called the
+ answer, which indicates which communications means are accepted, the
+ parameters that apply to those means, and addresses for receiving
+ media from the offerer. An offer/answer exchange is within the
+ context of a dialog, so that if a SIP INVITE results in multiple
+ dialogs, each is a separate offer/answer exchange. The offer/answer
+ model defines restrictions on when offers and answers can be made
+ (for example, you cannot make a new offer while one is in progress).
+ This results in restrictions on where the offers and answers can
+ appear in SIP messages. In this specification, offers and answers
+ can only appear in INVITE requests and responses, and ACK. The usage
+ of offers and answers is further restricted. For the initial INVITE
+ transaction, the rules are:
+
+ o The initial offer MUST be in either an INVITE or, if not there,
+ in the first reliable non-failure message from the UAS back to
+ the UAC. In this specification, that is the final 2xx
+ response.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 79]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o If the initial offer is in an INVITE, the answer MUST be in a
+ reliable non-failure message from UAS back to UAC which is
+ correlated to that INVITE. For this specification, that is
+ only the final 2xx response to that INVITE. That same exact
+ answer MAY also be placed in any provisional responses sent
+ prior to the answer. The UAC MUST treat the first session
+ description it receives as the answer, and MUST ignore any
+ session descriptions in subsequent responses to the initial
+ INVITE.
+
+ o If the initial offer is in the first reliable non-failure
+ message from the UAS back to UAC, the answer MUST be in the
+ acknowledgement for that message (in this specification, ACK
+ for a 2xx response).
+
+ o After having sent or received an answer to the first offer, the
+ UAC MAY generate subsequent offers in requests based on rules
+ specified for that method, but only if it has received answers
+ to any previous offers, and has not sent any offers to which it
+ hasn't gotten an answer.
+
+ o Once the UAS has sent or received an answer to the initial
+ offer, it MUST NOT generate subsequent offers in any responses
+ to the initial INVITE. This means that a UAS based on this
+ specification alone can never generate subsequent offers until
+ completion of the initial transaction.
+
+ Concretely, the above rules specify two exchanges for UAs compliant
+ to this specification alone - the offer is in the INVITE, and the
+ answer in the 2xx (and possibly in a 1xx as well, with the same
+ value), or the offer is in the 2xx, and the answer is in the ACK.
+ All user agents that support INVITE MUST support these two exchanges.
+
+ The Session Description Protocol (SDP) (RFC 2327 [1]) MUST be
+ supported by all user agents as a means to describe sessions, and its
+ usage for constructing offers and answers MUST follow the procedures
+ defined in [13].
+
+ The restrictions of the offer-answer model just described only apply
+ to bodies whose Content-Disposition header field value is "session".
+ Therefore, it is possible that both the INVITE and the ACK contain a
+ body message (for example, the INVITE carries a photo (Content-
+ Disposition: render) and the ACK a session description (Content-
+ Disposition: session)).
+
+ If the Content-Disposition header field is missing, bodies of
+ Content-Type application/sdp imply the disposition "session", while
+ other content types imply "render".
+
+
+
+Rosenberg, et. al. Standards Track [Page 80]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Once the INVITE has been created, the UAC follows the procedures
+ defined for sending requests outside of a dialog (Section 8). This
+ results in the construction of a client transaction that will
+ ultimately send the request and deliver responses to the UAC.
+
+13.2.2 Processing INVITE Responses
+
+ Once the INVITE has been passed to the INVITE client transaction, the
+ UAC waits for responses for the INVITE. If the INVITE client
+ transaction returns a timeout rather than a response the TU acts as
+ if a 408 (Request Timeout) response had been received, as described
+ in Section 8.1.3.
+
+13.2.2.1 1xx Responses
+
+ Zero, one or multiple provisional responses may arrive before one or
+ more final responses are received. Provisional responses for an
+ INVITE request can create "early dialogs". If a provisional response
+ has a tag in the To field, and if the dialog ID of the response does
+ not match an existing dialog, one is constructed using the procedures
+ defined in Section 12.1.2.
+
+ The early dialog will only be needed if the UAC needs to send a
+ request to its peer within the dialog before the initial INVITE
+ transaction completes. Header fields present in a provisional
+ response are applicable as long as the dialog is in the early state
+ (for example, an Allow header field in a provisional response
+ contains the methods that can be used in the dialog while this is in
+ the early state).
+
+13.2.2.2 3xx Responses
+
+ A 3xx response may contain one or more Contact header field values
+ providing new addresses where the callee might be reachable.
+ Depending on the status code of the 3xx response (see Section 21.3),
+ the UAC MAY choose to try those new addresses.
+
+13.2.2.3 4xx, 5xx and 6xx Responses
+
+ A single non-2xx final response may be received for the INVITE. 4xx,
+ 5xx and 6xx responses may contain a Contact header field value
+ indicating the location where additional information about the error
+ can be found. Subsequent final responses (which would only arrive
+ under error conditions) MUST be ignored.
+
+ All early dialogs are considered terminated upon reception of the
+ non-2xx final response.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 81]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ After having received the non-2xx final response the UAC core
+ considers the INVITE transaction completed. The INVITE client
+ transaction handles the generation of ACKs for the response (see
+ Section 17).
+
+13.2.2.4 2xx Responses
+
+ Multiple 2xx responses may arrive at the UAC for a single INVITE
+ request due to a forking proxy. Each response is distinguished by
+ the tag parameter in the To header field, and each represents a
+ distinct dialog, with a distinct dialog identifier.
+
+ If the dialog identifier in the 2xx response matches the dialog
+ identifier of an existing dialog, the dialog MUST be transitioned to
+ the "confirmed" state, and the route set for the dialog MUST be
+ recomputed based on the 2xx response using the procedures of Section
+ 12.2.1.2. Otherwise, a new dialog in the "confirmed" state MUST be
+ constructed using the procedures of Section 12.1.2.
+
+ Note that the only piece of state that is recomputed is the route
+ set. Other pieces of state such as the highest sequence numbers
+ (remote and local) sent within the dialog are not recomputed. The
+ route set only is recomputed for backwards compatibility. RFC
+ 2543 did not mandate mirroring of the Record-Route header field in
+ a 1xx, only 2xx. However, we cannot update the entire state of
+ the dialog, since mid-dialog requests may have been sent within
+ the early dialog, modifying the sequence numbers, for example.
+
+ The UAC core MUST generate an ACK request for each 2xx received from
+ the transaction layer. The header fields of the ACK are constructed
+ in the same way as for any request sent within a dialog (see Section
+ 12) with the exception of the CSeq and the header fields related to
+ authentication. The sequence number of the CSeq header field MUST be
+ the same as the INVITE being acknowledged, but the CSeq method MUST
+ be ACK. The ACK MUST contain the same credentials as the INVITE. If
+ the 2xx contains an offer (based on the rules above), the ACK MUST
+ carry an answer in its body. If the offer in the 2xx response is not
+ acceptable, the UAC core MUST generate a valid answer in the ACK and
+ then send a BYE immediately.
+
+ Once the ACK has been constructed, the procedures of [4] are used to
+ determine the destination address, port and transport. However, the
+ request is passed to the transport layer directly for transmission,
+ rather than a client transaction. This is because the UAC core
+ handles retransmissions of the ACK, not the transaction layer. The
+ ACK MUST be passed to the client transport every time a
+ retransmission of the 2xx final response that triggered the ACK
+ arrives.
+
+
+
+Rosenberg, et. al. Standards Track [Page 82]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The UAC core considers the INVITE transaction completed 64*T1 seconds
+ after the reception of the first 2xx response. At this point all the
+ early dialogs that have not transitioned to established dialogs are
+ terminated. Once the INVITE transaction is considered completed by
+ the UAC core, no more new 2xx responses are expected to arrive.
+
+ If, after acknowledging any 2xx response to an INVITE, the UAC does
+ not want to continue with that dialog, then the UAC MUST terminate
+ the dialog by sending a BYE request as described in Section 15.
+
+13.3 UAS Processing
+
+13.3.1 Processing of the INVITE
+
+ The UAS core will receive INVITE requests from the transaction layer.
+ It first performs the request processing procedures of Section 8.2,
+ which are applied for both requests inside and outside of a dialog.
+
+ Assuming these processing states are completed without generating a
+ response, the UAS core performs the additional processing steps:
+
+ 1. If the request is an INVITE that contains an Expires header
+ field, the UAS core sets a timer for the number of seconds
+ indicated in the header field value. When the timer fires, the
+ invitation is considered to be expired. If the invitation
+ expires before the UAS has generated a final response, a 487
+ (Request Terminated) response SHOULD be generated.
+
+ 2. If the request is a mid-dialog request, the method-independent
+ processing described in Section 12.2.2 is first applied. It
+ might also modify the session; Section 14 provides details.
+
+ 3. If the request has a tag in the To header field but the dialog
+ identifier does not match any of the existing dialogs, the UAS
+ may have crashed and restarted, or may have received a request
+ for a different (possibly failed) UAS. Section 12.2.2 provides
+ guidelines to achieve a robust behavior under such a situation.
+
+ Processing from here forward assumes that the INVITE is outside of a
+ dialog, and is thus for the purposes of establishing a new session.
+
+ The INVITE may contain a session description, in which case the UAS
+ is being presented with an offer for that session. It is possible
+ that the user is already a participant in that session, even though
+ the INVITE is outside of a dialog. This can happen when a user is
+ invited to the same multicast conference by multiple other
+ participants. If desired, the UAS MAY use identifiers within the
+ session description to detect this duplication. For example, SDP
+
+
+
+Rosenberg, et. al. Standards Track [Page 83]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ contains a session id and version number in the origin (o) field. If
+ the user is already a member of the session, and the session
+ parameters contained in the session description have not changed, the
+ UAS MAY silently accept the INVITE (that is, send a 2xx response
+ without prompting the user).
+
+ If the INVITE does not contain a session description, the UAS is
+ being asked to participate in a session, and the UAC has asked that
+ the UAS provide the offer of the session. It MUST provide the offer
+ in its first non-failure reliable message back to the UAC. In this
+ specification, that is a 2xx response to the INVITE.
+
+ The UAS can indicate progress, accept, redirect, or reject the
+ invitation. In all of these cases, it formulates a response using
+ the procedures described in Section 8.2.6.
+
+13.3.1.1 Progress
+
+ If the UAS is not able to answer the invitation immediately, it can
+ choose to indicate some kind of progress to the UAC (for example, an
+ indication that a phone is ringing). This is accomplished with a
+ provisional response between 101 and 199. These provisional
+ responses establish early dialogs and therefore follow the procedures
+ of Section 12.1.1 in addition to those of Section 8.2.6. A UAS MAY
+ send as many provisional responses as it likes. Each of these MUST
+ indicate the same dialog ID. However, these will not be delivered
+ reliably.
+
+ If the UAS desires an extended period of time to answer the INVITE,
+ it will need to ask for an "extension" in order to prevent proxies
+ from canceling the transaction. A proxy has the option of canceling
+ a transaction when there is a gap of 3 minutes between responses in a
+ transaction. To prevent cancellation, the UAS MUST send a non-100
+ provisional response at every minute, to handle the possibility of
+ lost provisional responses.
+
+ An INVITE transaction can go on for extended durations when the
+ user is placed on hold, or when interworking with PSTN systems
+ which allow communications to take place without answering the
+ call. The latter is common in Interactive Voice Response (IVR)
+ systems.
+
+13.3.1.2 The INVITE is Redirected
+
+ If the UAS decides to redirect the call, a 3xx response is sent. A
+ 300 (Multiple Choices), 301 (Moved Permanently) or 302 (Moved
+ Temporarily) response SHOULD contain a Contact header field
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 84]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ containing one or more URIs of new addresses to be tried. The
+ response is passed to the INVITE server transaction, which will deal
+ with its retransmissions.
+
+13.3.1.3 The INVITE is Rejected
+
+ A common scenario occurs when the callee is currently not willing or
+ able to take additional calls at this end system. A 486 (Busy Here)
+ SHOULD be returned in such a scenario. If the UAS knows that no
+ other end system will be able to accept this call, a 600 (Busy
+ Everywhere) response SHOULD be sent instead. However, it is unlikely
+ that a UAS will be able to know this in general, and thus this
+ response will not usually be used. The response is passed to the
+ INVITE server transaction, which will deal with its retransmissions.
+
+ A UAS rejecting an offer contained in an INVITE SHOULD return a 488
+ (Not Acceptable Here) response. Such a response SHOULD include a
+ Warning header field value explaining why the offer was rejected.
+
+13.3.1.4 The INVITE is Accepted
+
+ The UAS core generates a 2xx response. This response establishes a
+ dialog, and therefore follows the procedures of Section 12.1.1 in
+ addition to those of Section 8.2.6.
+
+ A 2xx response to an INVITE SHOULD contain the Allow header field and
+ the Supported header field, and MAY contain the Accept header field.
+ Including these header fields allows the UAC to determine the
+ features and extensions supported by the UAS for the duration of the
+ call, without probing.
+
+ If the INVITE request contained an offer, and the UAS had not yet
+ sent an answer, the 2xx MUST contain an answer. If the INVITE did
+ not contain an offer, the 2xx MUST contain an offer if the UAS had
+ not yet sent an offer.
+
+ Once the response has been constructed, it is passed to the INVITE
+ server transaction. Note, however, that the INVITE server
+ transaction will be destroyed as soon as it receives this final
+ response and passes it to the transport. Therefore, it is necessary
+ to periodically pass the response directly to the transport until the
+ ACK arrives. The 2xx response is passed to the transport with an
+ interval that starts at T1 seconds and doubles for each
+ retransmission until it reaches T2 seconds (T1 and T2 are defined in
+ Section 17). Response retransmissions cease when an ACK request for
+ the response is received. This is independent of whatever transport
+ protocols are used to send the response.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 85]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Since 2xx is retransmitted end-to-end, there may be hops between
+ UAS and UAC that are UDP. To ensure reliable delivery across
+ these hops, the response is retransmitted periodically even if the
+ transport at the UAS is reliable.
+
+ If the server retransmits the 2xx response for 64*T1 seconds without
+ receiving an ACK, the dialog is confirmed, but the session SHOULD be
+ terminated. This is accomplished with a BYE, as described in Section
+ 15.
+
+14 Modifying an Existing Session
+
+ A successful INVITE request (see Section 13) establishes both a
+ dialog between two user agents and a session using the offer-answer
+ model. Section 12 explains how to modify an existing dialog using a
+ target refresh request (for example, changing the remote target URI
+ of the dialog). This section describes how to modify the actual
+ session. This modification can involve changing addresses or ports,
+ adding a media stream, deleting a media stream, and so on. This is
+ accomplished by sending a new INVITE request within the same dialog
+ that established the session. An INVITE request sent within an
+ existing dialog is known as a re-INVITE.
+
+ Note that a single re-INVITE can modify the dialog and the
+ parameters of the session at the same time.
+
+ Either the caller or callee can modify an existing session.
+
+ The behavior of a UA on detection of media failure is a matter of
+ local policy. However, automated generation of re-INVITE or BYE is
+ NOT RECOMMENDED to avoid flooding the network with traffic when there
+ is congestion. In any case, if these messages are sent
+ automatically, they SHOULD be sent after some randomized interval.
+
+ Note that the paragraph above refers to automatically generated
+ BYEs and re-INVITEs. If the user hangs up upon media failure, the
+ UA would send a BYE request as usual.
+
+14.1 UAC Behavior
+
+ The same offer-answer model that applies to session descriptions in
+ INVITEs (Section 13.2.1) applies to re-INVITEs. As a result, a UAC
+ that wants to add a media stream, for example, will create a new
+ offer that contains this media stream, and send that in an INVITE
+ request to its peer. It is important to note that the full
+ description of the session, not just the change, is sent. This
+ supports stateless session processing in various elements, and
+ supports failover and recovery capabilities. Of course, a UAC MAY
+
+
+
+Rosenberg, et. al. Standards Track [Page 86]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ send a re-INVITE with no session description, in which case the first
+ reliable non-failure response to the re-INVITE will contain the offer
+ (in this specification, that is a 2xx response).
+
+ If the session description format has the capability for version
+ numbers, the offerer SHOULD indicate that the version of the session
+ description has changed.
+
+ The To, From, Call-ID, CSeq, and Request-URI of a re-INVITE are set
+ following the same rules as for regular requests within an existing
+ dialog, described in Section 12.
+
+ A UAC MAY choose not to add an Alert-Info header field or a body with
+ Content-Disposition "alert" to re-INVITEs because UASs do not
+ typically alert the user upon reception of a re-INVITE.
+
+ Unlike an INVITE, which can fork, a re-INVITE will never fork, and
+ therefore, only ever generate a single final response. The reason a
+ re-INVITE will never fork is that the Request-URI identifies the
+ target as the UA instance it established the dialog with, rather than
+ identifying an address-of-record for the user.
+
+ Note that a UAC MUST NOT initiate a new INVITE transaction within a
+ dialog while another INVITE transaction is in progress in either
+ direction.
+
+ 1. If there is an ongoing INVITE client transaction, the TU MUST
+ wait until the transaction reaches the completed or terminated
+ state before initiating the new INVITE.
+
+ 2. If there is an ongoing INVITE server transaction, the TU MUST
+ wait until the transaction reaches the confirmed or terminated
+ state before initiating the new INVITE.
+
+ However, a UA MAY initiate a regular transaction while an INVITE
+ transaction is in progress. A UA MAY also initiate an INVITE
+ transaction while a regular transaction is in progress.
+
+ If a UA receives a non-2xx final response to a re-INVITE, the session
+ parameters MUST remain unchanged, as if no re-INVITE had been issued.
+ Note that, as stated in Section 12.2.1.2, if the non-2xx final
+ response is a 481 (Call/Transaction Does Not Exist), or a 408
+ (Request Timeout), or no response at all is received for the re-
+ INVITE (that is, a timeout is returned by the INVITE client
+ transaction), the UAC will terminate the dialog.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 87]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ If a UAC receives a 491 response to a re-INVITE, it SHOULD start a
+ timer with a value T chosen as follows:
+
+ 1. If the UAC is the owner of the Call-ID of the dialog ID
+ (meaning it generated the value), T has a randomly chosen value
+ between 2.1 and 4 seconds in units of 10 ms.
+
+ 2. If the UAC is not the owner of the Call-ID of the dialog ID, T
+ has a randomly chosen value of between 0 and 2 seconds in units
+ of 10 ms.
+
+ When the timer fires, the UAC SHOULD attempt the re-INVITE once more,
+ if it still desires for that session modification to take place. For
+ example, if the call was already hung up with a BYE, the re-INVITE
+ would not take place.
+
+ The rules for transmitting a re-INVITE and for generating an ACK for
+ a 2xx response to re-INVITE are the same as for the initial INVITE
+ (Section 13.2.1).
+
+14.2 UAS Behavior
+
+ Section 13.3.1 describes the procedure for distinguishing incoming
+ re-INVITEs from incoming initial INVITEs and handling a re-INVITE for
+ an existing dialog.
+
+ A UAS that receives a second INVITE before it sends the final
+ response to a first INVITE with a lower CSeq sequence number on the
+ same dialog MUST return a 500 (Server Internal Error) response to the
+ second INVITE and MUST include a Retry-After header field with a
+ randomly chosen value of between 0 and 10 seconds.
+
+ A UAS that receives an INVITE on a dialog while an INVITE it had sent
+ on that dialog is in progress MUST return a 491 (Request Pending)
+ response to the received INVITE.
+
+ If a UA receives a re-INVITE for an existing dialog, it MUST check
+ any version identifiers in the session description or, if there are
+ no version identifiers, the content of the session description to see
+ if it has changed. If the session description has changed, the UAS
+ MUST adjust the session parameters accordingly, possibly after asking
+ the user for confirmation.
+
+ Versioning of the session description can be used to accommodate
+ the capabilities of new arrivals to a conference, add or delete
+ media, or change from a unicast to a multicast conference.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 88]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ If the new session description is not acceptable, the UAS can reject
+ it by returning a 488 (Not Acceptable Here) response for the re-
+ INVITE. This response SHOULD include a Warning header field.
+
+ If a UAS generates a 2xx response and never receives an ACK, it
+ SHOULD generate a BYE to terminate the dialog.
+
+ A UAS MAY choose not to generate 180 (Ringing) responses for a re-
+ INVITE because UACs do not typically render this information to the
+ user. For the same reason, UASs MAY choose not to use an Alert-Info
+ header field or a body with Content-Disposition "alert" in responses
+ to a re-INVITE.
+
+ A UAS providing an offer in a 2xx (because the INVITE did not contain
+ an offer) SHOULD construct the offer as if the UAS were making a
+ brand new call, subject to the constraints of sending an offer that
+ updates an existing session, as described in [13] in the case of SDP.
+ Specifically, this means that it SHOULD include as many media formats
+ and media types that the UA is willing to support. The UAS MUST
+ ensure that the session description overlaps with its previous
+ session description in media formats, transports, or other parameters
+ that require support from the peer. This is to avoid the need for
+ the peer to reject the session description. If, however, it is
+ unacceptable to the UAC, the UAC SHOULD generate an answer with a
+ valid session description, and then send a BYE to terminate the
+ session.
+
+15 Terminating a Session
+
+ This section describes the procedures for terminating a session
+ established by SIP. The state of the session and the state of the
+ dialog are very closely related. When a session is initiated with an
+ INVITE, each 1xx or 2xx response from a distinct UAS creates a
+ dialog, and if that response completes the offer/answer exchange, it
+ also creates a session. As a result, each session is "associated"
+ with a single dialog - the one which resulted in its creation. If an
+ initial INVITE generates a non-2xx final response, that terminates
+ all sessions (if any) and all dialogs (if any) that were created
+ through responses to the request. By virtue of completing the
+ transaction, a non-2xx final response also prevents further sessions
+ from being created as a result of the INVITE. The BYE request is
+ used to terminate a specific session or attempted session. In this
+ case, the specific session is the one with the peer UA on the other
+ side of the dialog. When a BYE is received on a dialog, any session
+ associated with that dialog SHOULD terminate. A UA MUST NOT send a
+ BYE outside of a dialog. The caller's UA MAY send a BYE for either
+ confirmed or early dialogs, and the callee's UA MAY send a BYE on
+ confirmed dialogs, but MUST NOT send a BYE on early dialogs.
+
+
+
+Rosenberg, et. al. Standards Track [Page 89]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ However, the callee's UA MUST NOT send a BYE on a confirmed dialog
+ until it has received an ACK for its 2xx response or until the server
+ transaction times out. If no SIP extensions have defined other
+ application layer states associated with the dialog, the BYE also
+ terminates the dialog.
+
+ The impact of a non-2xx final response to INVITE on dialogs and
+ sessions makes the use of CANCEL attractive. The CANCEL attempts to
+ force a non-2xx response to the INVITE (in particular, a 487).
+ Therefore, if a UAC wishes to give up on its call attempt entirely,
+ it can send a CANCEL. If the INVITE results in 2xx final response(s)
+ to the INVITE, this means that a UAS accepted the invitation while
+ the CANCEL was in progress. The UAC MAY continue with the sessions
+ established by any 2xx responses, or MAY terminate them with BYE.
+
+ The notion of "hanging up" is not well defined within SIP. It is
+ specific to a particular, albeit common, user interface.
+ Typically, when the user hangs up, it indicates a desire to
+ terminate the attempt to establish a session, and to terminate any
+ sessions already created. For the caller's UA, this would imply a
+ CANCEL request if the initial INVITE has not generated a final
+ response, and a BYE to all confirmed dialogs after a final
+ response. For the callee's UA, it would typically imply a BYE;
+ presumably, when the user picked up the phone, a 2xx was
+ generated, and so hanging up would result in a BYE after the ACK
+ is received. This does not mean a user cannot hang up before
+ receipt of the ACK, it just means that the software in his phone
+ needs to maintain state for a short while in order to clean up
+ properly. If the particular UI allows for the user to reject a
+ call before its answered, a 403 (Forbidden) is a good way to
+ express that. As per the rules above, a BYE can't be sent.
+
+15.1 Terminating a Session with a BYE Request
+
+15.1.1 UAC Behavior
+
+ A BYE request is constructed as would any other request within a
+ dialog, as described in Section 12.
+
+ Once the BYE is constructed, the UAC core creates a new non-INVITE
+ client transaction, and passes it the BYE request. The UAC MUST
+ consider the session terminated (and therefore stop sending or
+ listening for media) as soon as the BYE request is passed to the
+ client transaction. If the response for the BYE is a 481
+ (Call/Transaction Does Not Exist) or a 408 (Request Timeout) or no
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 90]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ response at all is received for the BYE (that is, a timeout is
+ returned by the client transaction), the UAC MUST consider the
+ session and the dialog terminated.
+
+15.1.2 UAS Behavior
+
+ A UAS first processes the BYE request according to the general UAS
+ processing described in Section 8.2. A UAS core receiving a BYE
+ request checks if it matches an existing dialog. If the BYE does not
+ match an existing dialog, the UAS core SHOULD generate a 481
+ (Call/Transaction Does Not Exist) response and pass that to the
+ server transaction.
+
+ This rule means that a BYE sent without tags by a UAC will be
+ rejected. This is a change from RFC 2543, which allowed BYE
+ without tags.
+
+ A UAS core receiving a BYE request for an existing dialog MUST follow
+ the procedures of Section 12.2.2 to process the request. Once done,
+ the UAS SHOULD terminate the session (and therefore stop sending and
+ listening for media). The only case where it can elect not to are
+ multicast sessions, where participation is possible even if the other
+ participant in the dialog has terminated its involvement in the
+ session. Whether or not it ends its participation on the session,
+ the UAS core MUST generate a 2xx response to the BYE, and MUST pass
+ that to the server transaction for transmission.
+
+ The UAS MUST still respond to any pending requests received for that
+ dialog. It is RECOMMENDED that a 487 (Request Terminated) response
+ be generated to those pending requests.
+
+16 Proxy Behavior
+
+16.1 Overview
+
+ SIP proxies are elements that route SIP requests to user agent
+ servers and SIP responses to user agent clients. A request may
+ traverse several proxies on its way to a UAS. Each will make routing
+ decisions, modifying the request before forwarding it to the next
+ element. Responses will route through the same set of proxies
+ traversed by the request in the reverse order.
+
+ Being a proxy is a logical role for a SIP element. When a request
+ arrives, an element that can play the role of a proxy first decides
+ if it needs to respond to the request on its own. For instance, the
+ request may be malformed or the element may need credentials from the
+ client before acting as a proxy. The element MAY respond with any
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 91]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ appropriate error code. When responding directly to a request, the
+ element is playing the role of a UAS and MUST behave as described in
+ Section 8.2.
+
+ A proxy can operate in either a stateful or stateless mode for each
+ new request. When stateless, a proxy acts as a simple forwarding
+ element. It forwards each request downstream to a single element
+ determined by making a targeting and routing decision based on the
+ request. It simply forwards every response it receives upstream. A
+ stateless proxy discards information about a message once the message
+ has been forwarded. A stateful proxy remembers information
+ (specifically, transaction state) about each incoming request and any
+ requests it sends as a result of processing the incoming request. It
+ uses this information to affect the processing of future messages
+ associated with that request. A stateful proxy MAY choose to "fork"
+ a request, routing it to multiple destinations. Any request that is
+ forwarded to more than one location MUST be handled statefully.
+
+ In some circumstances, a proxy MAY forward requests using stateful
+ transports (such as TCP) without being transaction-stateful. For
+ instance, a proxy MAY forward a request from one TCP connection to
+ another transaction statelessly as long as it places enough
+ information in the message to be able to forward the response down
+ the same connection the request arrived on. Requests forwarded
+ between different types of transports where the proxy's TU must take
+ an active role in ensuring reliable delivery on one of the transports
+ MUST be forwarded transaction statefully.
+
+ A stateful proxy MAY transition to stateless operation at any time
+ during the processing of a request, so long as it did not do anything
+ that would otherwise prevent it from being stateless initially
+ (forking, for example, or generation of a 100 response). When
+ performing such a transition, all state is simply discarded. The
+ proxy SHOULD NOT initiate a CANCEL request.
+
+ Much of the processing involved when acting statelessly or statefully
+ for a request is identical. The next several subsections are written
+ from the point of view of a stateful proxy. The last section calls
+ out those places where a stateless proxy behaves differently.
+
+16.2 Stateful Proxy
+
+ When stateful, a proxy is purely a SIP transaction processing engine.
+ Its behavior is modeled here in terms of the server and client
+ transactions defined in Section 17. A stateful proxy has a server
+ transaction associated with one or more client transactions by a
+ higher layer proxy processing component (see figure 3), known as a
+ proxy core. An incoming request is processed by a server
+
+
+
+Rosenberg, et. al. Standards Track [Page 92]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ transaction. Requests from the server transaction are passed to a
+ proxy core. The proxy core determines where to route the request,
+ choosing one or more next-hop locations. An outgoing request for
+ each next-hop location is processed by its own associated client
+ transaction. The proxy core collects the responses from the client
+ transactions and uses them to send responses to the server
+ transaction.
+
+ A stateful proxy creates a new server transaction for each new
+ request received. Any retransmissions of the request will then be
+ handled by that server transaction per Section 17. The proxy core
+ MUST behave as a UAS with respect to sending an immediate provisional
+ on that server transaction (such as 100 Trying) as described in
+ Section 8.2.6. Thus, a stateful proxy SHOULD NOT generate 100
+ (Trying) responses to non-INVITE requests.
+
+ This is a model of proxy behavior, not of software. An
+ implementation is free to take any approach that replicates the
+ external behavior this model defines.
+
+ For all new requests, including any with unknown methods, an element
+ intending to proxy the request MUST:
+
+ 1. Validate the request (Section 16.3)
+
+ 2. Preprocess routing information (Section 16.4)
+
+ 3. Determine target(s) for the request (Section 16.5)
+
+ +--------------------+
+ | | +---+
+ | | | C |
+ | | | T |
+ | | +---+
+ +---+ | Proxy | +---+ CT = Client Transaction
+ | S | | "Higher" Layer | | C |
+ | T | | | | T | ST = Server Transaction
+ +---+ | | +---+
+ | | +---+
+ | | | C |
+ | | | T |
+ | | +---+
+ +--------------------+
+
+ Figure 3: Stateful Proxy Model
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 93]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 4. Forward the request to each target (Section 16.6)
+
+ 5. Process all responses (Section 16.7)
+
+16.3 Request Validation
+
+ Before an element can proxy a request, it MUST verify the message's
+ validity. A valid message must pass the following checks:
+
+ 1. Reasonable Syntax
+
+ 2. URI scheme
+
+ 3. Max-Forwards
+
+ 4. (Optional) Loop Detection
+
+ 5. Proxy-Require
+
+ 6. Proxy-Authorization
+
+ If any of these checks fail, the element MUST behave as a user agent
+ server (see Section 8.2) and respond with an error code.
+
+ Notice that a proxy is not required to detect merged requests and
+ MUST NOT treat merged requests as an error condition. The endpoints
+ receiving the requests will resolve the merge as described in Section
+ 8.2.2.2.
+
+ 1. Reasonable syntax check
+
+ The request MUST be well-formed enough to be handled with a server
+ transaction. Any components involved in the remainder of these
+ Request Validation steps or the Request Forwarding section MUST be
+ well-formed. Any other components, well-formed or not, SHOULD be
+ ignored and remain unchanged when the message is forwarded. For
+ instance, an element would not reject a request because of a
+ malformed Date header field. Likewise, a proxy would not remove a
+ malformed Date header field before forwarding a request.
+
+ This protocol is designed to be extended. Future extensions may
+ define new methods and header fields at any time. An element MUST
+ NOT refuse to proxy a request because it contains a method or
+ header field it does not know about.
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 94]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 2. URI scheme check
+
+ If the Request-URI has a URI whose scheme is not understood by the
+ proxy, the proxy SHOULD reject the request with a 416 (Unsupported
+ URI Scheme) response.
+
+ 3. Max-Forwards check
+
+ The Max-Forwards header field (Section 20.22) is used to limit the
+ number of elements a SIP request can traverse.
+
+ If the request does not contain a Max-Forwards header field, this
+ check is passed.
+
+ If the request contains a Max-Forwards header field with a field
+ value greater than zero, the check is passed.
+
+ If the request contains a Max-Forwards header field with a field
+ value of zero (0), the element MUST NOT forward the request. If
+ the request was for OPTIONS, the element MAY act as the final
+ recipient and respond per Section 11. Otherwise, the element MUST
+ return a 483 (Too many hops) response.
+
+ 4. Optional Loop Detection check
+
+ An element MAY check for forwarding loops before forwarding a
+ request. If the request contains a Via header field with a sent-
+ by value that equals a value placed into previous requests by the
+ proxy, the request has been forwarded by this element before. The
+ request has either looped or is legitimately spiraling through the
+ element. To determine if the request has looped, the element MAY
+ perform the branch parameter calculation described in Step 8 of
+ Section 16.6 on this message and compare it to the parameter
+ received in that Via header field. If the parameters match, the
+ request has looped. If they differ, the request is spiraling, and
+ processing continues. If a loop is detected, the element MAY
+ return a 482 (Loop Detected) response.
+
+ 5. Proxy-Require check
+
+ Future extensions to this protocol may introduce features that
+ require special handling by proxies. Endpoints will include a
+ Proxy-Require header field in requests that use these features,
+ telling the proxy not to process the request unless the feature is
+ understood.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 95]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ If the request contains a Proxy-Require header field (Section
+ 20.29) with one or more option-tags this element does not
+ understand, the element MUST return a 420 (Bad Extension)
+ response. The response MUST include an Unsupported (Section
+ 20.40) header field listing those option-tags the element did not
+ understand.
+
+ 6. Proxy-Authorization check
+
+ If an element requires credentials before forwarding a request,
+ the request MUST be inspected as described in Section 22.3. That
+ section also defines what the element must do if the inspection
+ fails.
+
+16.4 Route Information Preprocessing
+
+ The proxy MUST inspect the Request-URI of the request. If the
+ Request-URI of the request contains a value this proxy previously
+ placed into a Record-Route header field (see Section 16.6 item 4),
+ the proxy MUST replace the Request-URI in the request with the last
+ value from the Route header field, and remove that value from the
+ Route header field. The proxy MUST then proceed as if it received
+ this modified request.
+
+ This will only happen when the element sending the request to the
+ proxy (which may have been an endpoint) is a strict router. This
+ rewrite on receive is necessary to enable backwards compatibility
+ with those elements. It also allows elements following this
+ specification to preserve the Request-URI through strict-routing
+ proxies (see Section 12.2.1.1).
+
+ This requirement does not obligate a proxy to keep state in order
+ to detect URIs it previously placed in Record-Route header fields.
+ Instead, a proxy need only place enough information in those URIs
+ to recognize them as values it provided when they later appear.
+
+ If the Request-URI contains a maddr parameter, the proxy MUST check
+ to see if its value is in the set of addresses or domains the proxy
+ is configured to be responsible for. If the Request-URI has a maddr
+ parameter with a value the proxy is responsible for, and the request
+ was received using the port and transport indicated (explicitly or by
+ default) in the Request-URI, the proxy MUST strip the maddr and any
+ non-default port or transport parameter and continue processing as if
+ those values had not been present in the request.
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 96]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ A request may arrive with a maddr matching the proxy, but on a
+ port or transport different from that indicated in the URI. Such
+ a request needs to be forwarded to the proxy using the indicated
+ port and transport.
+
+ If the first value in the Route header field indicates this proxy,
+ the proxy MUST remove that value from the request.
+
+16.5 Determining Request Targets
+
+ Next, the proxy calculates the target(s) of the request. The set of
+ targets will either be predetermined by the contents of the request
+ or will be obtained from an abstract location service. Each target
+ in the set is represented as a URI.
+
+ If the Request-URI of the request contains an maddr parameter, the
+ Request-URI MUST be placed into the target set as the only target
+ URI, and the proxy MUST proceed to Section 16.6.
+
+ If the domain of the Request-URI indicates a domain this element is
+ not responsible for, the Request-URI MUST be placed into the target
+ set as the only target, and the element MUST proceed to the task of
+ Request Forwarding (Section 16.6).
+
+ There are many circumstances in which a proxy might receive a
+ request for a domain it is not responsible for. A firewall proxy
+ handling outgoing calls (the way HTTP proxies handle outgoing
+ requests) is an example of where this is likely to occur.
+
+ If the target set for the request has not been predetermined as
+ described above, this implies that the element is responsible for the
+ domain in the Request-URI, and the element MAY use whatever mechanism
+ it desires to determine where to send the request. Any of these
+ mechanisms can be modeled as accessing an abstract Location Service.
+ This may consist of obtaining information from a location service
+ created by a SIP Registrar, reading a database, consulting a presence
+ server, utilizing other protocols, or simply performing an
+ algorithmic substitution on the Request-URI. When accessing the
+ location service constructed by a registrar, the Request-URI MUST
+ first be canonicalized as described in Section 10.3 before being used
+ as an index. The output of these mechanisms is used to construct the
+ target set.
+
+ If the Request-URI does not provide sufficient information for the
+ proxy to determine the target set, it SHOULD return a 485 (Ambiguous)
+ response. This response SHOULD contain a Contact header field
+ containing URIs of new addresses to be tried. For example, an INVITE
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 97]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ to sip:John.Smith@company.com may be ambiguous at a proxy whose
+ location service has multiple John Smiths listed. See Section
+ 21.4.23 for details.
+
+ Any information in or about the request or the current environment of
+ the element MAY be used in the construction of the target set. For
+ instance, different sets may be constructed depending on contents or
+ the presence of header fields and bodies, the time of day of the
+ request's arrival, the interface on which the request arrived,
+ failure of previous requests, or even the element's current level of
+ utilization.
+
+ As potential targets are located through these services, their URIs
+ are added to the target set. Targets can only be placed in the
+ target set once. If a target URI is already present in the set
+ (based on the definition of equality for the URI type), it MUST NOT
+ be added again.
+
+ A proxy MUST NOT add additional targets to the target set if the
+ Request-URI of the original request does not indicate a resource this
+ proxy is responsible for.
+
+ A proxy can only change the Request-URI of a request during
+ forwarding if it is responsible for that URI. If the proxy is not
+ responsible for that URI, it will not recurse on 3xx or 416
+ responses as described below.
+
+ If the Request-URI of the original request indicates a resource this
+ proxy is responsible for, the proxy MAY continue to add targets to
+ the set after beginning Request Forwarding. It MAY use any
+ information obtained during that processing to determine new targets.
+ For instance, a proxy may choose to incorporate contacts obtained in
+ a redirect response (3xx) into the target set. If a proxy uses a
+ dynamic source of information while building the target set (for
+ instance, if it consults a SIP Registrar), it SHOULD monitor that
+ source for the duration of processing the request. New locations
+ SHOULD be added to the target set as they become available. As
+ above, any given URI MUST NOT be added to the set more than once.
+
+ Allowing a URI to be added to the set only once reduces
+ unnecessary network traffic, and in the case of incorporating
+ contacts from redirect requests prevents infinite recursion.
+
+ For example, a trivial location service is a "no-op", where the
+ target URI is equal to the incoming request URI. The request is sent
+ to a specific next hop proxy for further processing. During request
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 98]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ forwarding of Section 16.6, Item 6, the identity of that next hop,
+ expressed as a SIP or SIPS URI, is inserted as the top-most Route
+ header field value into the request.
+
+ If the Request-URI indicates a resource at this proxy that does not
+ exist, the proxy MUST return a 404 (Not Found) response.
+
+ If the target set remains empty after applying all of the above, the
+ proxy MUST return an error response, which SHOULD be the 480
+ (Temporarily Unavailable) response.
+
+16.6 Request Forwarding
+
+ As soon as the target set is non-empty, a proxy MAY begin forwarding
+ the request. A stateful proxy MAY process the set in any order. It
+ MAY process multiple targets serially, allowing each client
+ transaction to complete before starting the next. It MAY start
+ client transactions with every target in parallel. It also MAY
+ arbitrarily divide the set into groups, processing the groups
+ serially and processing the targets in each group in parallel.
+
+ A common ordering mechanism is to use the qvalue parameter of targets
+ obtained from Contact header fields (see Section 20.10). Targets are
+ processed from highest qvalue to lowest. Targets with equal qvalues
+ may be processed in parallel.
+
+ A stateful proxy must have a mechanism to maintain the target set as
+ responses are received and associate the responses to each forwarded
+ request with the original request. For the purposes of this model,
+ this mechanism is a "response context" created by the proxy layer
+ before forwarding the first request.
+
+ For each target, the proxy forwards the request following these
+ steps:
+
+ 1. Make a copy of the received request
+
+ 2. Update the Request-URI
+
+ 3. Update the Max-Forwards header field
+
+ 4. Optionally add a Record-route header field value
+
+ 5. Optionally add additional header fields
+
+ 6. Postprocess routing information
+
+ 7. Determine the next-hop address, port, and transport
+
+
+
+Rosenberg, et. al. Standards Track [Page 99]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 8. Add a Via header field value
+
+ 9. Add a Content-Length header field if necessary
+
+ 10. Forward the new request
+
+ 11. Set timer C
+
+ Each of these steps is detailed below:
+
+ 1. Copy request
+
+ The proxy starts with a copy of the received request. The copy
+ MUST initially contain all of the header fields from the
+ received request. Fields not detailed in the processing
+ described below MUST NOT be removed. The copy SHOULD maintain
+ the ordering of the header fields as in the received request.
+ The proxy MUST NOT reorder field values with a common field
+ name (See Section 7.3.1). The proxy MUST NOT add to, modify,
+ or remove the message body.
+
+ An actual implementation need not perform a copy; the primary
+ requirement is that the processing for each next hop begin with
+ the same request.
+
+ 2. Request-URI
+
+ The Request-URI in the copy's start line MUST be replaced with
+ the URI for this target. If the URI contains any parameters
+ not allowed in a Request-URI, they MUST be removed.
+
+ This is the essence of a proxy's role. This is the mechanism
+ through which a proxy routes a request toward its destination.
+
+ In some circumstances, the received Request-URI is placed into
+ the target set without being modified. For that target, the
+ replacement above is effectively a no-op.
+
+ 3. Max-Forwards
+
+ If the copy contains a Max-Forwards header field, the proxy
+ MUST decrement its value by one (1).
+
+ If the copy does not contain a Max-Forwards header field, the
+ proxy MUST add one with a field value, which SHOULD be 70.
+
+ Some existing UAs will not provide a Max-Forwards header field
+ in a request.
+
+
+
+Rosenberg, et. al. Standards Track [Page 100]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 4. Record-Route
+
+ If this proxy wishes to remain on the path of future requests
+ in a dialog created by this request (assuming the request
+ creates a dialog), it MUST insert a Record-Route header field
+ value into the copy before any existing Record-Route header
+ field values, even if a Route header field is already present.
+
+ Requests establishing a dialog may contain a preloaded Route
+ header field.
+
+ If this request is already part of a dialog, the proxy SHOULD
+ insert a Record-Route header field value if it wishes to remain
+ on the path of future requests in the dialog. In normal
+ endpoint operation as described in Section 12, these Record-
+ Route header field values will not have any effect on the route
+ sets used by the endpoints.
+
+ The proxy will remain on the path if it chooses to not insert a
+ Record-Route header field value into requests that are already
+ part of a dialog. However, it would be removed from the path
+ when an endpoint that has failed reconstitutes the dialog.
+
+ A proxy MAY insert a Record-Route header field value into any
+ request. If the request does not initiate a dialog, the
+ endpoints will ignore the value. See Section 12 for details on
+ how endpoints use the Record-Route header field values to
+ construct Route header fields.
+
+ Each proxy in the path of a request chooses whether to add a
+ Record-Route header field value independently - the presence of
+ a Record-Route header field in a request does not obligate this
+ proxy to add a value.
+
+ The URI placed in the Record-Route header field value MUST be a
+ SIP or SIPS URI. This URI MUST contain an lr parameter (see
+ Section 19.1.1). This URI MAY be different for each
+ destination the request is forwarded to. The URI SHOULD NOT
+ contain the transport parameter unless the proxy has knowledge
+ (such as in a private network) that the next downstream element
+ that will be in the path of subsequent requests supports that
+ transport.
+
+ The URI this proxy provides will be used by some other element
+ to make a routing decision. This proxy, in general, has no way
+ of knowing the capabilities of that element, so it must
+ restrict itself to the mandatory elements of a SIP
+ implementation: SIP URIs and either the TCP or UDP transports.
+
+
+
+Rosenberg, et. al. Standards Track [Page 101]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The URI placed in the Record-Route header field MUST resolve to
+ the element inserting it (or a suitable stand-in) when the
+ server location procedures of [4] are applied to it, so that
+ subsequent requests reach the same SIP element. If the
+ Request-URI contains a SIPS URI, or the topmost Route header
+ field value (after the post processing of bullet 6) contains a
+ SIPS URI, the URI placed into the Record-Route header field
+ MUST be a SIPS URI. Furthermore, if the request was not
+ received over TLS, the proxy MUST insert a Record-Route header
+ field. In a similar fashion, a proxy that receives a request
+ over TLS, but generates a request without a SIPS URI in the
+ Request-URI or topmost Route header field value (after the post
+ processing of bullet 6), MUST insert a Record-Route header
+ field that is not a SIPS URI.
+
+ A proxy at a security perimeter must remain on the perimeter
+ throughout the dialog.
+
+ If the URI placed in the Record-Route header field needs to be
+ rewritten when it passes back through in a response, the URI
+ MUST be distinct enough to locate at that time. (The request
+ may spiral through this proxy, resulting in more than one
+ Record-Route header field value being added). Item 8 of
+ Section 16.7 recommends a mechanism to make the URI
+ sufficiently distinct.
+
+ The proxy MAY include parameters in the Record-Route header
+ field value. These will be echoed in some responses to the
+ request such as the 200 (OK) responses to INVITE. Such
+ parameters may be useful for keeping state in the message
+ rather than the proxy.
+
+ If a proxy needs to be in the path of any type of dialog (such
+ as one straddling a firewall), it SHOULD add a Record-Route
+ header field value to every request with a method it does not
+ understand since that method may have dialog semantics.
+
+ The URI a proxy places into a Record-Route header field is only
+ valid for the lifetime of any dialog created by the transaction
+ in which it occurs. A dialog-stateful proxy, for example, MAY
+ refuse to accept future requests with that value in the
+ Request-URI after the dialog has terminated. Non-dialog-
+ stateful proxies, of course, have no concept of when the dialog
+ has terminated, but they MAY encode enough information in the
+ value to compare it against the dialog identifier of future
+ requests and MAY reject requests not matching that information.
+ Endpoints MUST NOT use a URI obtained from a Record-Route
+ header field outside the dialog in which it was provided. See
+
+
+
+Rosenberg, et. al. Standards Track [Page 102]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Section 12 for more information on an endpoint's use of
+ Record-Route header fields.
+
+ Record-routing may be required by certain services where the
+ proxy needs to observe all messages in a dialog. However, it
+ slows down processing and impairs scalability and thus proxies
+ should only record-route if required for a particular service.
+
+ The Record-Route process is designed to work for any SIP
+ request that initiates a dialog. INVITE is the only such
+ request in this specification, but extensions to the protocol
+ MAY define others.
+
+ 5. Add Additional Header Fields
+
+ The proxy MAY add any other appropriate header fields to the
+ copy at this point.
+
+ 6. Postprocess routing information
+
+ A proxy MAY have a local policy that mandates that a request
+ visit a specific set of proxies before being delivered to the
+ destination. A proxy MUST ensure that all such proxies are
+ loose routers. Generally, this can only be known with
+ certainty if the proxies are within the same administrative
+ domain. This set of proxies is represented by a set of URIs
+ (each of which contains the lr parameter). This set MUST be
+ pushed into the Route header field of the copy ahead of any
+ existing values, if present. If the Route header field is
+ absent, it MUST be added, containing that list of URIs.
+
+ If the proxy has a local policy that mandates that the request
+ visit one specific proxy, an alternative to pushing a Route
+ value into the Route header field is to bypass the forwarding
+ logic of item 10 below, and instead just send the request to
+ the address, port, and transport for that specific proxy. If
+ the request has a Route header field, this alternative MUST NOT
+ be used unless it is known that next hop proxy is a loose
+ router. Otherwise, this approach MAY be used, but the Route
+ insertion mechanism above is preferred for its robustness,
+ flexibility, generality and consistency of operation.
+ Furthermore, if the Request-URI contains a SIPS URI, TLS MUST
+ be used to communicate with that proxy.
+
+ If the copy contains a Route header field, the proxy MUST
+ inspect the URI in its first value. If that URI does not
+ contain an lr parameter, the proxy MUST modify the copy as
+ follows:
+
+
+
+Rosenberg, et. al. Standards Track [Page 103]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ - The proxy MUST place the Request-URI into the Route header
+ field as the last value.
+
+ - The proxy MUST then place the first Route header field value
+ into the Request-URI and remove that value from the Route
+ header field.
+
+ Appending the Request-URI to the Route header field is part of
+ a mechanism used to pass the information in that Request-URI
+ through strict-routing elements. "Popping" the first Route
+ header field value into the Request-URI formats the message the
+ way a strict-routing element expects to receive it (with its
+ own URI in the Request-URI and the next location to visit in
+ the first Route header field value).
+
+ 7. Determine Next-Hop Address, Port, and Transport
+
+ The proxy MAY have a local policy to send the request to a
+ specific IP address, port, and transport, independent of the
+ values of the Route and Request-URI. Such a policy MUST NOT be
+ used if the proxy is not certain that the IP address, port, and
+ transport correspond to a server that is a loose router.
+ However, this mechanism for sending the request through a
+ specific next hop is NOT RECOMMENDED; instead a Route header
+ field should be used for that purpose as described above.
+
+ In the absence of such an overriding mechanism, the proxy
+ applies the procedures listed in [4] as follows to determine
+ where to send the request. If the proxy has reformatted the
+ request to send to a strict-routing element as described in
+ step 6 above, the proxy MUST apply those procedures to the
+ Request-URI of the request. Otherwise, the proxy MUST apply
+ the procedures to the first value in the Route header field, if
+ present, else the Request-URI. The procedures will produce an
+ ordered set of (address, port, transport) tuples.
+ Independently of which URI is being used as input to the
+ procedures of [4], if the Request-URI specifies a SIPS
+ resource, the proxy MUST follow the procedures of [4] as if the
+ input URI were a SIPS URI.
+
+ As described in [4], the proxy MUST attempt to deliver the
+ message to the first tuple in that set, and proceed through the
+ set in order until the delivery attempt succeeds.
+
+ For each tuple attempted, the proxy MUST format the message as
+ appropriate for the tuple and send the request using a new
+ client transaction as detailed in steps 8 through 10.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 104]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Since each attempt uses a new client transaction, it represents
+ a new branch. Thus, the branch parameter provided with the Via
+ header field inserted in step 8 MUST be different for each
+ attempt.
+
+ If the client transaction reports failure to send the request
+ or a timeout from its state machine, the proxy continues to the
+ next address in that ordered set. If the ordered set is
+ exhausted, the request cannot be forwarded to this element in
+ the target set. The proxy does not need to place anything in
+ the response context, but otherwise acts as if this element of
+ the target set returned a 408 (Request Timeout) final response.
+
+ 8. Add a Via header field value
+
+ The proxy MUST insert a Via header field value into the copy
+ before the existing Via header field values. The construction
+ of this value follows the same guidelines of Section 8.1.1.7.
+ This implies that the proxy will compute its own branch
+ parameter, which will be globally unique for that branch, and
+ contain the requisite magic cookie. Note that this implies that
+ the branch parameter will be different for different instances
+ of a spiraled or looped request through a proxy.
+
+ Proxies choosing to detect loops have an additional constraint
+ in the value they use for construction of the branch parameter.
+ A proxy choosing to detect loops SHOULD create a branch
+ parameter separable into two parts by the implementation. The
+ first part MUST satisfy the constraints of Section 8.1.1.7 as
+ described above. The second is used to perform loop detection
+ and distinguish loops from spirals.
+
+ Loop detection is performed by verifying that, when a request
+ returns to a proxy, those fields having an impact on the
+ processing of the request have not changed. The value placed
+ in this part of the branch parameter SHOULD reflect all of
+ those fields (including any Route, Proxy-Require and Proxy-
+ Authorization header fields). This is to ensure that if the
+ request is routed back to the proxy and one of those fields
+ changes, it is treated as a spiral and not a loop (see Section
+ 16.3). A common way to create this value is to compute a
+ cryptographic hash of the To tag, From tag, Call-ID header
+ field, the Request-URI of the request received (before
+ translation), the topmost Via header, and the sequence number
+ from the CSeq header field, in addition to any Proxy-Require
+ and Proxy-Authorization header fields that may be present. The
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 105]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ algorithm used to compute the hash is implementation-dependent,
+ but MD5 (RFC 1321 [35]), expressed in hexadecimal, is a
+ reasonable choice. (Base64 is not permissible for a token.)
+
+ If a proxy wishes to detect loops, the "branch" parameter it
+ supplies MUST depend on all information affecting processing of
+ a request, including the incoming Request-URI and any header
+ fields affecting the request's admission or routing. This is
+ necessary to distinguish looped requests from requests whose
+ routing parameters have changed before returning to this
+ server.
+
+ The request method MUST NOT be included in the calculation of
+ the branch parameter. In particular, CANCEL and ACK requests
+ (for non-2xx responses) MUST have the same branch value as the
+ corresponding request they cancel or acknowledge. The branch
+ parameter is used in correlating those requests at the server
+ handling them (see Sections 17.2.3 and 9.2).
+
+ 9. Add a Content-Length header field if necessary
+
+ If the request will be sent to the next hop using a stream-
+ based transport and the copy contains no Content-Length header
+ field, the proxy MUST insert one with the correct value for the
+ body of the request (see Section 20.14).
+
+ 10. Forward Request
+
+ A stateful proxy MUST create a new client transaction for this
+ request as described in Section 17.1 and instructs the
+ transaction to send the request using the address, port and
+ transport determined in step 7.
+
+ 11. Set timer C
+
+ In order to handle the case where an INVITE request never
+ generates a final response, the TU uses a timer which is called
+ timer C. Timer C MUST be set for each client transaction when
+ an INVITE request is proxied. The timer MUST be larger than 3
+ minutes. Section 16.7 bullet 2 discusses how this timer is
+ updated with provisional responses, and Section 16.8 discusses
+ processing when it fires.
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 106]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+16.7 Response Processing
+
+ When a response is received by an element, it first tries to locate a
+ client transaction (Section 17.1.3) matching the response. If none
+ is found, the element MUST process the response (even if it is an
+ informational response) as a stateless proxy (described below). If a
+ match is found, the response is handed to the client transaction.
+
+ Forwarding responses for which a client transaction (or more
+ generally any knowledge of having sent an associated request) is
+ not found improves robustness. In particular, it ensures that
+ "late" 2xx responses to INVITE requests are forwarded properly.
+
+ As client transactions pass responses to the proxy layer, the
+ following processing MUST take place:
+
+ 1. Find the appropriate response context
+
+ 2. Update timer C for provisional responses
+
+ 3. Remove the topmost Via
+
+ 4. Add the response to the response context
+
+ 5. Check to see if this response should be forwarded immediately
+
+ 6. When necessary, choose the best final response from the
+ response context
+
+ If no final response has been forwarded after every client
+ transaction associated with the response context has been terminated,
+ the proxy must choose and forward the "best" response from those it
+ has seen so far.
+
+ The following processing MUST be performed on each response that is
+ forwarded. It is likely that more than one response to each request
+ will be forwarded: at least each provisional and one final response.
+
+ 7. Aggregate authorization header field values if necessary
+
+ 8. Optionally rewrite Record-Route header field values
+
+ 9. Forward the response
+
+ 10. Generate any necessary CANCEL requests
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 107]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Each of the above steps are detailed below:
+
+ 1. Find Context
+
+ The proxy locates the "response context" it created before
+ forwarding the original request using the key described in
+ Section 16.6. The remaining processing steps take place in
+ this context.
+
+ 2. Update timer C for provisional responses
+
+ For an INVITE transaction, if the response is a provisional
+ response with status codes 101 to 199 inclusive (i.e., anything
+ but 100), the proxy MUST reset timer C for that client
+ transaction. The timer MAY be reset to a different value, but
+ this value MUST be greater than 3 minutes.
+
+ 3. Via
+
+ The proxy removes the topmost Via header field value from the
+ response.
+
+ If no Via header field values remain in the response, the
+ response was meant for this element and MUST NOT be forwarded.
+ The remainder of the processing described in this section is
+ not performed on this message, the UAC processing rules
+ described in Section 8.1.3 are followed instead (transport
+ layer processing has already occurred).
+
+ This will happen, for instance, when the element generates
+ CANCEL requests as described in Section 10.
+
+ 4. Add response to context
+
+ Final responses received are stored in the response context
+ until a final response is generated on the server transaction
+ associated with this context. The response may be a candidate
+ for the best final response to be returned on that server
+ transaction. Information from this response may be needed in
+ forming the best response, even if this response is not chosen.
+
+ If the proxy chooses to recurse on any contacts in a 3xx
+ response by adding them to the target set, it MUST remove them
+ from the response before adding the response to the response
+ context. However, a proxy SHOULD NOT recurse to a non-SIPS URI
+ if the Request-URI of the original request was a SIPS URI. If
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 108]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ the proxy recurses on all of the contacts in a 3xx response,
+ the proxy SHOULD NOT add the resulting contactless response to
+ the response context.
+
+ Removing the contact before adding the response to the response
+ context prevents the next element upstream from retrying a
+ location this proxy has already attempted.
+
+ 3xx responses may contain a mixture of SIP, SIPS, and non-SIP
+ URIs. A proxy may choose to recurse on the SIP and SIPS URIs
+ and place the remainder into the response context to be
+ returned, potentially in the final response.
+
+ If a proxy receives a 416 (Unsupported URI Scheme) response to
+ a request whose Request-URI scheme was not SIP, but the scheme
+ in the original received request was SIP or SIPS (that is, the
+ proxy changed the scheme from SIP or SIPS to something else
+ when it proxied a request), the proxy SHOULD add a new URI to
+ the target set. This URI SHOULD be a SIP URI version of the
+ non-SIP URI that was just tried. In the case of the tel URL,
+ this is accomplished by placing the telephone-subscriber part
+ of the tel URL into the user part of the SIP URI, and setting
+ the hostpart to the domain where the prior request was sent.
+ See Section 19.1.6 for more detail on forming SIP URIs from tel
+ URLs.
+
+ As with a 3xx response, if a proxy "recurses" on the 416 by
+ trying a SIP or SIPS URI instead, the 416 response SHOULD NOT
+ be added to the response context.
+
+ 5. Check response for forwarding
+
+ Until a final response has been sent on the server transaction,
+ the following responses MUST be forwarded immediately:
+
+ - Any provisional response other than 100 (Trying)
+
+ - Any 2xx response
+
+ If a 6xx response is received, it is not immediately forwarded,
+ but the stateful proxy SHOULD cancel all client pending
+ transactions as described in Section 10, and it MUST NOT create
+ any new branches in this context.
+
+ This is a change from RFC 2543, which mandated that the proxy
+ was to forward the 6xx response immediately. For an INVITE
+ transaction, this approach had the problem that a 2xx response
+ could arrive on another branch, in which case the proxy would
+
+
+
+Rosenberg, et. al. Standards Track [Page 109]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ have to forward the 2xx. The result was that the UAC could
+ receive a 6xx response followed by a 2xx response, which should
+ never be allowed to happen. Under the new rules, upon
+ receiving a 6xx, a proxy will issue a CANCEL request, which
+ will generally result in 487 responses from all outstanding
+ client transactions, and then at that point the 6xx is
+ forwarded upstream.
+
+ After a final response has been sent on the server transaction,
+ the following responses MUST be forwarded immediately:
+
+ - Any 2xx response to an INVITE request
+
+ A stateful proxy MUST NOT immediately forward any other
+ responses. In particular, a stateful proxy MUST NOT forward
+ any 100 (Trying) response. Those responses that are candidates
+ for forwarding later as the "best" response have been gathered
+ as described in step "Add Response to Context".
+
+ Any response chosen for immediate forwarding MUST be processed
+ as described in steps "Aggregate Authorization Header Field
+ Values" through "Record-Route".
+
+ This step, combined with the next, ensures that a stateful
+ proxy will forward exactly one final response to a non-INVITE
+ request, and either exactly one non-2xx response or one or more
+ 2xx responses to an INVITE request.
+
+ 6. Choosing the best response
+
+ A stateful proxy MUST send a final response to a response
+ context's server transaction if no final responses have been
+ immediately forwarded by the above rules and all client
+ transactions in this response context have been terminated.
+
+ The stateful proxy MUST choose the "best" final response among
+ those received and stored in the response context.
+
+ If there are no final responses in the context, the proxy MUST
+ send a 408 (Request Timeout) response to the server
+ transaction.
+
+ Otherwise, the proxy MUST forward a response from the responses
+ stored in the response context. It MUST choose from the 6xx
+ class responses if any exist in the context. If no 6xx class
+ responses are present, the proxy SHOULD choose from the lowest
+ response class stored in the response context. The proxy MAY
+ select any response within that chosen class. The proxy SHOULD
+
+
+
+Rosenberg, et. al. Standards Track [Page 110]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ give preference to responses that provide information affecting
+ resubmission of this request, such as 401, 407, 415, 420, and
+ 484 if the 4xx class is chosen.
+
+ A proxy which receives a 503 (Service Unavailable) response
+ SHOULD NOT forward it upstream unless it can determine that any
+ subsequent requests it might proxy will also generate a 503.
+ In other words, forwarding a 503 means that the proxy knows it
+ cannot service any requests, not just the one for the Request-
+ URI in the request which generated the 503. If the only
+ response that was received is a 503, the proxy SHOULD generate
+ a 500 response and forward that upstream.
+
+ The forwarded response MUST be processed as described in steps
+ "Aggregate Authorization Header Field Values" through "Record-
+ Route".
+
+ For example, if a proxy forwarded a request to 4 locations, and
+ received 503, 407, 501, and 404 responses, it may choose to
+ forward the 407 (Proxy Authentication Required) response.
+
+ 1xx and 2xx responses may be involved in the establishment of
+ dialogs. When a request does not contain a To tag, the To tag
+ in the response is used by the UAC to distinguish multiple
+ responses to a dialog creating request. A proxy MUST NOT
+ insert a tag into the To header field of a 1xx or 2xx response
+ if the request did not contain one. A proxy MUST NOT modify
+ the tag in the To header field of a 1xx or 2xx response.
+
+ Since a proxy may not insert a tag into the To header field of
+ a 1xx response to a request that did not contain one, it cannot
+ issue non-100 provisional responses on its own. However, it
+ can branch the request to a UAS sharing the same element as the
+ proxy. This UAS can return its own provisional responses,
+ entering into an early dialog with the initiator of the
+ request. The UAS does not have to be a discreet process from
+ the proxy. It could be a virtual UAS implemented in the same
+ code space as the proxy.
+
+ 3-6xx responses are delivered hop-by-hop. When issuing a 3-6xx
+ response, the element is effectively acting as a UAS, issuing
+ its own response, usually based on the responses received from
+ downstream elements. An element SHOULD preserve the To tag
+ when simply forwarding a 3-6xx response to a request that did
+ not contain a To tag.
+
+ A proxy MUST NOT modify the To tag in any forwarded response to
+ a request that contains a To tag.
+
+
+
+Rosenberg, et. al. Standards Track [Page 111]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ While it makes no difference to the upstream elements if the
+ proxy replaced the To tag in a forwarded 3-6xx response,
+ preserving the original tag may assist with debugging.
+
+ When the proxy is aggregating information from several
+ responses, choosing a To tag from among them is arbitrary, and
+ generating a new To tag may make debugging easier. This
+ happens, for instance, when combining 401 (Unauthorized) and
+ 407 (Proxy Authentication Required) challenges, or combining
+ Contact values from unencrypted and unauthenticated 3xx
+ responses.
+
+ 7. Aggregate Authorization Header Field Values
+
+ If the selected response is a 401 (Unauthorized) or 407 (Proxy
+ Authentication Required), the proxy MUST collect any WWW-
+ Authenticate and Proxy-Authenticate header field values from
+ all other 401 (Unauthorized) and 407 (Proxy Authentication
+ Required) responses received so far in this response context
+ and add them to this response without modification before
+ forwarding. The resulting 401 (Unauthorized) or 407 (Proxy
+ Authentication Required) response could have several WWW-
+ Authenticate AND Proxy-Authenticate header field values.
+
+ This is necessary because any or all of the destinations the
+ request was forwarded to may have requested credentials. The
+ client needs to receive all of those challenges and supply
+ credentials for each of them when it retries the request.
+ Motivation for this behavior is provided in Section 26.
+
+ 8. Record-Route
+
+ If the selected response contains a Record-Route header field
+ value originally provided by this proxy, the proxy MAY choose
+ to rewrite the value before forwarding the response. This
+ allows the proxy to provide different URIs for itself to the
+ next upstream and downstream elements. A proxy may choose to
+ use this mechanism for any reason. For instance, it is useful
+ for multi-homed hosts.
+
+ If the proxy received the request over TLS, and sent it out
+ over a non-TLS connection, the proxy MUST rewrite the URI in
+ the Record-Route header field to be a SIPS URI. If the proxy
+ received the request over a non-TLS connection, and sent it out
+ over TLS, the proxy MUST rewrite the URI in the Record-Route
+ header field to be a SIP URI.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 112]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The new URI provided by the proxy MUST satisfy the same
+ constraints on URIs placed in Record-Route header fields in
+ requests (see Step 4 of Section 16.6) with the following
+ modifications:
+
+ The URI SHOULD NOT contain the transport parameter unless the
+ proxy has knowledge that the next upstream (as opposed to
+ downstream) element that will be in the path of subsequent
+ requests supports that transport.
+
+ When a proxy does decide to modify the Record-Route header
+ field in the response, one of the operations it performs is
+ locating the Record-Route value that it had inserted. If the
+ request spiraled, and the proxy inserted a Record-Route value
+ in each iteration of the spiral, locating the correct value in
+ the response (which must be the proper iteration in the reverse
+ direction) is tricky. The rules above recommend that a proxy
+ wishing to rewrite Record-Route header field values insert
+ sufficiently distinct URIs into the Record-Route header field
+ so that the right one may be selected for rewriting. A
+ RECOMMENDED mechanism to achieve this is for the proxy to
+ append a unique identifier for the proxy instance to the user
+ portion of the URI.
+
+ When the response arrives, the proxy modifies the first
+ Record-Route whose identifier matches the proxy instance. The
+ modification results in a URI without this piece of data
+ appended to the user portion of the URI. Upon the next
+ iteration, the same algorithm (find the topmost Record-Route
+ header field value with the parameter) will correctly extract
+ the next Record-Route header field value inserted by that
+ proxy.
+
+ Not every response to a request to which a proxy adds a
+ Record-Route header field value will contain a Record-Route
+ header field. If the response does contain a Record-Route
+ header field, it will contain the value the proxy added.
+
+ 9. Forward response
+
+ After performing the processing described in steps "Aggregate
+ Authorization Header Field Values" through "Record-Route", the
+ proxy MAY perform any feature specific manipulations on the
+ selected response. The proxy MUST NOT add to, modify, or
+ remove the message body. Unless otherwise specified, the proxy
+ MUST NOT remove any header field values other than the Via
+ header field value discussed in Section 16.7 Item 3. In
+ particular, the proxy MUST NOT remove any "received" parameter
+
+
+
+Rosenberg, et. al. Standards Track [Page 113]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ it may have added to the next Via header field value while
+ processing the request associated with this response. The
+ proxy MUST pass the response to the server transaction
+ associated with the response context. This will result in the
+ response being sent to the location now indicated in the
+ topmost Via header field value. If the server transaction is
+ no longer available to handle the transmission, the element
+ MUST forward the response statelessly by sending it to the
+ server transport. The server transaction might indicate
+ failure to send the response or signal a timeout in its state
+ machine. These errors would be logged for diagnostic purposes
+ as appropriate, but the protocol requires no remedial action
+ from the proxy.
+
+ The proxy MUST maintain the response context until all of its
+ associated transactions have been terminated, even after
+ forwarding a final response.
+
+ 10. Generate CANCELs
+
+ If the forwarded response was a final response, the proxy MUST
+ generate a CANCEL request for all pending client transactions
+ associated with this response context. A proxy SHOULD also
+ generate a CANCEL request for all pending client transactions
+ associated with this response context when it receives a 6xx
+ response. A pending client transaction is one that has
+ received a provisional response, but no final response (it is
+ in the proceeding state) and has not had an associated CANCEL
+ generated for it. Generating CANCEL requests is described in
+ Section 9.1.
+
+ The requirement to CANCEL pending client transactions upon
+ forwarding a final response does not guarantee that an endpoint
+ will not receive multiple 200 (OK) responses to an INVITE. 200
+ (OK) responses on more than one branch may be generated before
+ the CANCEL requests can be sent and processed. Further, it is
+ reasonable to expect that a future extension may override this
+ requirement to issue CANCEL requests.
+
+16.8 Processing Timer C
+
+ If timer C should fire, the proxy MUST either reset the timer with
+ any value it chooses, or terminate the client transaction. If the
+ client transaction has received a provisional response, the proxy
+ MUST generate a CANCEL request matching that transaction. If the
+ client transaction has not received a provisional response, the proxy
+ MUST behave as if the transaction received a 408 (Request Timeout)
+ response.
+
+
+
+Rosenberg, et. al. Standards Track [Page 114]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Allowing the proxy to reset the timer allows the proxy to dynamically
+ extend the transaction's lifetime based on current conditions (such
+ as utilization) when the timer fires.
+
+16.9 Handling Transport Errors
+
+ If the transport layer notifies a proxy of an error when it tries to
+ forward a request (see Section 18.4), the proxy MUST behave as if the
+ forwarded request received a 503 (Service Unavailable) response.
+
+ If the proxy is notified of an error when forwarding a response, it
+ drops the response. The proxy SHOULD NOT cancel any outstanding
+ client transactions associated with this response context due to this
+ notification.
+
+ If a proxy cancels its outstanding client transactions, a single
+ malicious or misbehaving client can cause all transactions to fail
+ through its Via header field.
+
+16.10 CANCEL Processing
+
+ A stateful proxy MAY generate a CANCEL to any other request it has
+ generated at any time (subject to receiving a provisional response to
+ that request as described in section 9.1). A proxy MUST cancel any
+ pending client transactions associated with a response context when
+ it receives a matching CANCEL request.
+
+ A stateful proxy MAY generate CANCEL requests for pending INVITE
+ client transactions based on the period specified in the INVITE's
+ Expires header field elapsing. However, this is generally
+ unnecessary since the endpoints involved will take care of signaling
+ the end of the transaction.
+
+ While a CANCEL request is handled in a stateful proxy by its own
+ server transaction, a new response context is not created for it.
+ Instead, the proxy layer searches its existing response contexts for
+ the server transaction handling the request associated with this
+ CANCEL. If a matching response context is found, the element MUST
+ immediately return a 200 (OK) response to the CANCEL request. In
+ this case, the element is acting as a user agent server as defined in
+ Section 8.2. Furthermore, the element MUST generate CANCEL requests
+ for all pending client transactions in the context as described in
+ Section 16.7 step 10.
+
+ If a response context is not found, the element does not have any
+ knowledge of the request to apply the CANCEL to. It MUST statelessly
+ forward the CANCEL request (it may have statelessly forwarded the
+ associated request previously).
+
+
+
+Rosenberg, et. al. Standards Track [Page 115]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+16.11 Stateless Proxy
+
+ When acting statelessly, a proxy is a simple message forwarder. Much
+ of the processing performed when acting statelessly is the same as
+ when behaving statefully. The differences are detailed here.
+
+ A stateless proxy does not have any notion of a transaction, or of
+ the response context used to describe stateful proxy behavior.
+ Instead, the stateless proxy takes messages, both requests and
+ responses, directly from the transport layer (See section 18). As a
+ result, stateless proxies do not retransmit messages on their own.
+ They do, however, forward all retransmissions they receive (they do
+ not have the ability to distinguish a retransmission from the
+ original message). Furthermore, when handling a request statelessly,
+ an element MUST NOT generate its own 100 (Trying) or any other
+ provisional response.
+
+ A stateless proxy MUST validate a request as described in Section
+ 16.3
+
+ A stateless proxy MUST follow the request processing steps described
+ in Sections 16.4 through 16.5 with the following exception:
+
+ o A stateless proxy MUST choose one and only one target from the
+ target set. This choice MUST only rely on fields in the
+ message and time-invariant properties of the server. In
+ particular, a retransmitted request MUST be forwarded to the
+ same destination each time it is processed. Furthermore,
+ CANCEL and non-Routed ACK requests MUST generate the same
+ choice as their associated INVITE.
+
+ A stateless proxy MUST follow the request processing steps described
+ in Section 16.6 with the following exceptions:
+
+ o The requirement for unique branch IDs across space and time
+ applies to stateless proxies as well. However, a stateless
+ proxy cannot simply use a random number generator to compute
+ the first component of the branch ID, as described in Section
+ 16.6 bullet 8. This is because retransmissions of a request
+ need to have the same value, and a stateless proxy cannot tell
+ a retransmission from the original request. Therefore, the
+ component of the branch parameter that makes it unique MUST be
+ the same each time a retransmitted request is forwarded. Thus
+ for a stateless proxy, the branch parameter MUST be computed as
+ a combinatoric function of message parameters which are
+ invariant on retransmission.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 116]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The stateless proxy MAY use any technique it likes to guarantee
+ uniqueness of its branch IDs across transactions. However, the
+ following procedure is RECOMMENDED. The proxy examines the
+ branch ID in the topmost Via header field of the received
+ request. If it begins with the magic cookie, the first
+ component of the branch ID of the outgoing request is computed
+ as a hash of the received branch ID. Otherwise, the first
+ component of the branch ID is computed as a hash of the topmost
+ Via, the tag in the To header field, the tag in the From header
+ field, the Call-ID header field, the CSeq number (but not
+ method), and the Request-URI from the received request. One of
+ these fields will always vary across two different
+ transactions.
+
+ o All other message transformations specified in Section 16.6
+ MUST result in the same transformation of a retransmitted
+ request. In particular, if the proxy inserts a Record-Route
+ value or pushes URIs into the Route header field, it MUST place
+ the same values in retransmissions of the request. As for the
+ Via branch parameter, this implies that the transformations
+ MUST be based on time-invariant configuration or
+ retransmission-invariant properties of the request.
+
+ o A stateless proxy determines where to forward the request as
+ described for stateful proxies in Section 16.6 Item 10. The
+ request is sent directly to the transport layer instead of
+ through a client transaction.
+
+ Since a stateless proxy must forward retransmitted requests to
+ the same destination and add identical branch parameters to
+ each of them, it can only use information from the message
+ itself and time-invariant configuration data for those
+ calculations. If the configuration state is not time-invariant
+ (for example, if a routing table is updated) any requests that
+ could be affected by the change may not be forwarded
+ statelessly during an interval equal to the transaction timeout
+ window before or after the change. The method of processing
+ the affected requests in that interval is an implementation
+ decision. A common solution is to forward them transaction
+ statefully.
+
+ Stateless proxies MUST NOT perform special processing for CANCEL
+ requests. They are processed by the above rules as any other
+ requests. In particular, a stateless proxy applies the same Route
+ header field processing to CANCEL requests that it applies to any
+ other request.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 117]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Response processing as described in Section 16.7 does not apply to a
+ proxy behaving statelessly. When a response arrives at a stateless
+ proxy, the proxy MUST inspect the sent-by value in the first
+ (topmost) Via header field value. If that address matches the proxy,
+ (it equals a value this proxy has inserted into previous requests)
+ the proxy MUST remove that header field value from the response and
+ forward the result to the location indicated in the next Via header
+ field value. The proxy MUST NOT add to, modify, or remove the
+ message body. Unless specified otherwise, the proxy MUST NOT remove
+ any other header field values. If the address does not match the
+ proxy, the message MUST be silently discarded.
+
+16.12 Summary of Proxy Route Processing
+
+ In the absence of local policy to the contrary, the processing a
+ proxy performs on a request containing a Route header field can be
+ summarized in the following steps.
+
+ 1. The proxy will inspect the Request-URI. If it indicates a
+ resource owned by this proxy, the proxy will replace it with
+ the results of running a location service. Otherwise, the
+ proxy will not change the Request-URI.
+
+ 2. The proxy will inspect the URI in the topmost Route header
+ field value. If it indicates this proxy, the proxy removes it
+ from the Route header field (this route node has been
+ reached).
+
+ 3. The proxy will forward the request to the resource indicated
+ by the URI in the topmost Route header field value or in the
+ Request-URI if no Route header field is present. The proxy
+ determines the address, port and transport to use when
+ forwarding the request by applying the procedures in [4] to
+ that URI.
+
+ If no strict-routing elements are encountered on the path of the
+ request, the Request-URI will always indicate the target of the
+ request.
+
+16.12.1 Examples
+
+16.12.1.1 Basic SIP Trapezoid
+
+ This scenario is the basic SIP trapezoid, U1 -> P1 -> P2 -> U2, with
+ both proxies record-routing. Here is the flow.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 118]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ U1 sends:
+
+ INVITE sip:callee@domain.com SIP/2.0
+ Contact: sip:caller@u1.example.com
+
+ to P1. P1 is an outbound proxy. P1 is not responsible for
+ domain.com, so it looks it up in DNS and sends it there. It also
+ adds a Record-Route header field value:
+
+ INVITE sip:callee@domain.com SIP/2.0
+ Contact: sip:caller@u1.example.com
+ Record-Route: <sip:p1.example.com;lr>
+
+ P2 gets this. It is responsible for domain.com so it runs a location
+ service and rewrites the Request-URI. It also adds a Record-Route
+ header field value. There is no Route header field, so it resolves
+ the new Request-URI to determine where to send the request:
+
+ INVITE sip:callee@u2.domain.com SIP/2.0
+ Contact: sip:caller@u1.example.com
+ Record-Route: <sip:p2.domain.com;lr>
+ Record-Route: <sip:p1.example.com;lr>
+
+ The callee at u2.domain.com gets this and responds with a 200 OK:
+
+ SIP/2.0 200 OK
+ Contact: sip:callee@u2.domain.com
+ Record-Route: <sip:p2.domain.com;lr>
+ Record-Route: <sip:p1.example.com;lr>
+
+ The callee at u2 also sets its dialog state's remote target URI to
+ sip:caller@u1.example.com and its route set to:
+
+ (<sip:p2.domain.com;lr>,<sip:p1.example.com;lr>)
+
+ This is forwarded by P2 to P1 to U1 as normal. Now, U1 sets its
+ dialog state's remote target URI to sip:callee@u2.domain.com and its
+ route set to:
+
+ (<sip:p1.example.com;lr>,<sip:p2.domain.com;lr>)
+
+ Since all the route set elements contain the lr parameter, U1
+ constructs the following BYE request:
+
+ BYE sip:callee@u2.domain.com SIP/2.0
+ Route: <sip:p1.example.com;lr>,<sip:p2.domain.com;lr>
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 119]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ As any other element (including proxies) would do, it resolves the
+ URI in the topmost Route header field value using DNS to determine
+ where to send the request. This goes to P1. P1 notices that it is
+ not responsible for the resource indicated in the Request-URI so it
+ doesn't change it. It does see that it is the first value in the
+ Route header field, so it removes that value, and forwards the
+ request to P2:
+
+ BYE sip:callee@u2.domain.com SIP/2.0
+ Route: <sip:p2.domain.com;lr>
+
+ P2 also notices it is not responsible for the resource indicated by
+ the Request-URI (it is responsible for domain.com, not
+ u2.domain.com), so it doesn't change it. It does see itself in the
+ first Route header field value, so it removes it and forwards the
+ following to u2.domain.com based on a DNS lookup against the
+ Request-URI:
+
+ BYE sip:callee@u2.domain.com SIP/2.0
+
+16.12.1.2 Traversing a Strict-Routing Proxy
+
+ In this scenario, a dialog is established across four proxies, each
+ of which adds Record-Route header field values. The third proxy
+ implements the strict-routing procedures specified in RFC 2543 and
+ many works in progress.
+
+ U1->P1->P2->P3->P4->U2
+
+ The INVITE arriving at U2 contains:
+
+ INVITE sip:callee@u2.domain.com SIP/2.0
+ Contact: sip:caller@u1.example.com
+ Record-Route: <sip:p4.domain.com;lr>
+ Record-Route: <sip:p3.middle.com>
+ Record-Route: <sip:p2.example.com;lr>
+ Record-Route: <sip:p1.example.com;lr>
+
+ Which U2 responds to with a 200 OK. Later, U2 sends the following
+ BYE request to P4 based on the first Route header field value.
+
+ BYE sip:caller@u1.example.com SIP/2.0
+ Route: <sip:p4.domain.com;lr>
+ Route: <sip:p3.middle.com>
+ Route: <sip:p2.example.com;lr>
+ Route: <sip:p1.example.com;lr>
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 120]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ P4 is not responsible for the resource indicated in the Request-URI
+ so it will leave it alone. It notices that it is the element in the
+ first Route header field value so it removes it. It then prepares to
+ send the request based on the now first Route header field value of
+ sip:p3.middle.com, but it notices that this URI does not contain the
+ lr parameter, so before sending, it reformats the request to be:
+
+ BYE sip:p3.middle.com SIP/2.0
+ Route: <sip:p2.example.com;lr>
+ Route: <sip:p1.example.com;lr>
+ Route: <sip:caller@u1.example.com>
+
+ P3 is a strict router, so it forwards the following to P2:
+
+ BYE sip:p2.example.com;lr SIP/2.0
+ Route: <sip:p1.example.com;lr>
+ Route: <sip:caller@u1.example.com>
+
+ P2 sees the request-URI is a value it placed into a Record-Route
+ header field, so before further processing, it rewrites the request
+ to be:
+
+ BYE sip:caller@u1.example.com SIP/2.0
+ Route: <sip:p1.example.com;lr>
+
+ P2 is not responsible for u1.example.com, so it sends the request to
+ P1 based on the resolution of the Route header field value.
+
+ P1 notices itself in the topmost Route header field value, so it
+ removes it, resulting in:
+
+ BYE sip:caller@u1.example.com SIP/2.0
+
+ Since P1 is not responsible for u1.example.com and there is no Route
+ header field, P1 will forward the request to u1.example.com based on
+ the Request-URI.
+
+16.12.1.3 Rewriting Record-Route Header Field Values
+
+ In this scenario, U1 and U2 are in different private namespaces and
+ they enter a dialog through a proxy P1, which acts as a gateway
+ between the namespaces.
+
+ U1->P1->U2
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 121]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ U1 sends:
+
+ INVITE sip:callee@gateway.leftprivatespace.com SIP/2.0
+ Contact: <sip:caller@u1.leftprivatespace.com>
+
+ P1 uses its location service and sends the following to U2:
+
+ INVITE sip:callee@rightprivatespace.com SIP/2.0
+ Contact: <sip:caller@u1.leftprivatespace.com>
+ Record-Route: <sip:gateway.rightprivatespace.com;lr>
+
+ U2 sends this 200 (OK) back to P1:
+
+ SIP/2.0 200 OK
+ Contact: <sip:callee@u2.rightprivatespace.com>
+ Record-Route: <sip:gateway.rightprivatespace.com;lr>
+
+ P1 rewrites its Record-Route header parameter to provide a value that
+ U1 will find useful, and sends the following to U1:
+
+ SIP/2.0 200 OK
+ Contact: <sip:callee@u2.rightprivatespace.com>
+ Record-Route: <sip:gateway.leftprivatespace.com;lr>
+
+ Later, U1 sends the following BYE request to P1:
+
+ BYE sip:callee@u2.rightprivatespace.com SIP/2.0
+ Route: <sip:gateway.leftprivatespace.com;lr>
+
+ which P1 forwards to U2 as:
+
+ BYE sip:callee@u2.rightprivatespace.com SIP/2.0
+
+17 Transactions
+
+ SIP is a transactional protocol: interactions between components take
+ place in a series of independent message exchanges. Specifically, a
+ SIP transaction consists of a single request and any responses to
+ that request, which include zero or more provisional responses and
+ one or more final responses. In the case of a transaction where the
+ request was an INVITE (known as an INVITE transaction), the
+ transaction also includes the ACK only if the final response was not
+ a 2xx response. If the response was a 2xx, the ACK is not considered
+ part of the transaction.
+
+ The reason for this separation is rooted in the importance of
+ delivering all 200 (OK) responses to an INVITE to the UAC. To
+ deliver them all to the UAC, the UAS alone takes responsibility
+
+
+
+Rosenberg, et. al. Standards Track [Page 122]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ for retransmitting them (see Section 13.3.1.4), and the UAC alone
+ takes responsibility for acknowledging them with ACK (see Section
+ 13.2.2.4). Since this ACK is retransmitted only by the UAC, it is
+ effectively considered its own transaction.
+
+ Transactions have a client side and a server side. The client side
+ is known as a client transaction and the server side as a server
+ transaction. The client transaction sends the request, and the
+ server transaction sends the response. The client and server
+ transactions are logical functions that are embedded in any number of
+ elements. Specifically, they exist within user agents and stateful
+ proxy servers. Consider the example in Section 4. In this example,
+ the UAC executes the client transaction, and its outbound proxy
+ executes the server transaction. The outbound proxy also executes a
+ client transaction, which sends the request to a server transaction
+ in the inbound proxy. That proxy also executes a client transaction,
+ which in turn sends the request to a server transaction in the UAS.
+ This is shown in Figure 4.
+
+ +---------+ +---------+ +---------+ +---------+
+ | +-+|Request |+-+ +-+|Request |+-+ +-+|Request |+-+ |
+ | |C||------->||S| |C||------->||S| |C||------->||S| |
+ | |l|| ||e| |l|| ||e| |l|| ||e| |
+ | |i|| ||r| |i|| ||r| |i|| ||r| |
+ | |e|| ||v| |e|| ||v| |e|| ||v| |
+ | |n|| ||e| |n|| ||e| |n|| ||e| |
+ | |t|| ||r| |t|| ||r| |t|| ||r| |
+ | | || || | | || || | | || || | |
+ | |T|| ||T| |T|| ||T| |T|| ||T| |
+ | |r|| ||r| |r|| ||r| |r|| ||r| |
+ | |a|| ||a| |a|| ||a| |a|| ||a| |
+ | |n|| ||n| |n|| ||n| |n|| ||n| |
+ | |s||Response||s| |s||Response||s| |s||Response||s| |
+ | +-+|<-------|+-+ +-+|<-------|+-+ +-+|<-------|+-+ |
+ +---------+ +---------+ +---------+ +---------+
+ UAC Outbound Inbound UAS
+ Proxy Proxy
+
+ Figure 4: Transaction relationships
+
+ A stateless proxy does not contain a client or server transaction.
+ The transaction exists between the UA or stateful proxy on one side,
+ and the UA or stateful proxy on the other side. As far as SIP
+ transactions are concerned, stateless proxies are effectively
+ transparent. The purpose of the client transaction is to receive a
+ request from the element in which the client is embedded (call this
+ element the "Transaction User" or TU; it can be a UA or a stateful
+ proxy), and reliably deliver the request to a server transaction.
+
+
+
+Rosenberg, et. al. Standards Track [Page 123]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The client transaction is also responsible for receiving responses
+ and delivering them to the TU, filtering out any response
+ retransmissions or disallowed responses (such as a response to ACK).
+ Additionally, in the case of an INVITE request, the client
+ transaction is responsible for generating the ACK request for any
+ final response accepting a 2xx response.
+
+ Similarly, the purpose of the server transaction is to receive
+ requests from the transport layer and deliver them to the TU. The
+ server transaction filters any request retransmissions from the
+ network. The server transaction accepts responses from the TU and
+ delivers them to the transport layer for transmission over the
+ network. In the case of an INVITE transaction, it absorbs the ACK
+ request for any final response excepting a 2xx response.
+
+ The 2xx response and its ACK receive special treatment. This
+ response is retransmitted only by a UAS, and its ACK generated only
+ by the UAC. This end-to-end treatment is needed so that a caller
+ knows the entire set of users that have accepted the call. Because
+ of this special handling, retransmissions of the 2xx response are
+ handled by the UA core, not the transaction layer. Similarly,
+ generation of the ACK for the 2xx is handled by the UA core. Each
+ proxy along the path merely forwards each 2xx response to INVITE and
+ its corresponding ACK.
+
+17.1 Client Transaction
+
+ The client transaction provides its functionality through the
+ maintenance of a state machine.
+
+ The TU communicates with the client transaction through a simple
+ interface. When the TU wishes to initiate a new transaction, it
+ creates a client transaction and passes it the SIP request to send
+ and an IP address, port, and transport to which to send it. The
+ client transaction begins execution of its state machine. Valid
+ responses are passed up to the TU from the client transaction.
+
+ There are two types of client transaction state machines, depending
+ on the method of the request passed by the TU. One handles client
+ transactions for INVITE requests. This type of machine is referred
+ to as an INVITE client transaction. Another type handles client
+ transactions for all requests except INVITE and ACK. This is
+ referred to as a non-INVITE client transaction. There is no client
+ transaction for ACK. If the TU wishes to send an ACK, it passes one
+ directly to the transport layer for transmission.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 124]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The INVITE transaction is different from those of other methods
+ because of its extended duration. Normally, human input is required
+ in order to respond to an INVITE. The long delays expected for
+ sending a response argue for a three-way handshake. On the other
+ hand, requests of other methods are expected to complete rapidly.
+ Because of the non-INVITE transaction's reliance on a two-way
+ handshake, TUs SHOULD respond immediately to non-INVITE requests.
+
+17.1.1 INVITE Client Transaction
+
+17.1.1.1 Overview of INVITE Transaction
+
+ The INVITE transaction consists of a three-way handshake. The client
+ transaction sends an INVITE, the server transaction sends responses,
+ and the client transaction sends an ACK. For unreliable transports
+ (such as UDP), the client transaction retransmits requests at an
+ interval that starts at T1 seconds and doubles after every
+ retransmission. T1 is an estimate of the round-trip time (RTT), and
+ it defaults to 500 ms. Nearly all of the transaction timers
+ described here scale with T1, and changing T1 adjusts their values.
+ The request is not retransmitted over reliable transports. After
+ receiving a 1xx response, any retransmissions cease altogether, and
+ the client waits for further responses. The server transaction can
+ send additional 1xx responses, which are not transmitted reliably by
+ the server transaction. Eventually, the server transaction decides
+ to send a final response. For unreliable transports, that response
+ is retransmitted periodically, and for reliable transports, it is
+ sent once. For each final response that is received at the client
+ transaction, the client transaction sends an ACK, the purpose of
+ which is to quench retransmissions of the response.
+
+17.1.1.2 Formal Description
+
+ The state machine for the INVITE client transaction is shown in
+ Figure 5. The initial state, "calling", MUST be entered when the TU
+ initiates a new client transaction with an INVITE request. The
+ client transaction MUST pass the request to the transport layer for
+ transmission (see Section 18). If an unreliable transport is being
+ used, the client transaction MUST start timer A with a value of T1.
+ If a reliable transport is being used, the client transaction SHOULD
+ NOT start timer A (Timer A controls request retransmissions). For
+ any transport, the client transaction MUST start timer B with a value
+ of 64*T1 seconds (Timer B controls transaction timeouts).
+
+ When timer A fires, the client transaction MUST retransmit the
+ request by passing it to the transport layer, and MUST reset the
+ timer with a value of 2*T1. The formal definition of retransmit
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 125]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ within the context of the transaction layer is to take the message
+ previously sent to the transport layer and pass it to the transport
+ layer once more.
+
+ When timer A fires 2*T1 seconds later, the request MUST be
+ retransmitted again (assuming the client transaction is still in this
+ state). This process MUST continue so that the request is
+ retransmitted with intervals that double after each transmission.
+ These retransmissions SHOULD only be done while the client
+ transaction is in the "calling" state.
+
+ The default value for T1 is 500 ms. T1 is an estimate of the RTT
+ between the client and server transactions. Elements MAY (though it
+ is NOT RECOMMENDED) use smaller values of T1 within closed, private
+ networks that do not permit general Internet connection. T1 MAY be
+ chosen larger, and this is RECOMMENDED if it is known in advance
+ (such as on high latency access links) that the RTT is larger.
+ Whatever the value of T1, the exponential backoffs on retransmissions
+ described in this section MUST be used.
+
+ If the client transaction is still in the "Calling" state when timer
+ B fires, the client transaction SHOULD inform the TU that a timeout
+ has occurred. The client transaction MUST NOT generate an ACK. The
+ value of 64*T1 is equal to the amount of time required to send seven
+ requests in the case of an unreliable transport.
+
+ If the client transaction receives a provisional response while in
+ the "Calling" state, it transitions to the "Proceeding" state. In the
+ "Proceeding" state, the client transaction SHOULD NOT retransmit the
+ request any longer. Furthermore, the provisional response MUST be
+ passed to the TU. Any further provisional responses MUST be passed
+ up to the TU while in the "Proceeding" state.
+
+ When in either the "Calling" or "Proceeding" states, reception of a
+ response with status code from 300-699 MUST cause the client
+ transaction to transition to "Completed". The client transaction
+ MUST pass the received response up to the TU, and the client
+ transaction MUST generate an ACK request, even if the transport is
+ reliable (guidelines for constructing the ACK from the response are
+ given in Section 17.1.1.3) and then pass the ACK to the transport
+ layer for transmission. The ACK MUST be sent to the same address,
+ port, and transport to which the original request was sent. The
+ client transaction SHOULD start timer D when it enters the
+ "Completed" state, with a value of at least 32 seconds for unreliable
+ transports, and a value of zero seconds for reliable transports.
+ Timer D reflects the amount of time that the server transaction can
+ remain in the "Completed" state when unreliable transports are used.
+ This is equal to Timer H in the INVITE server transaction, whose
+
+
+
+Rosenberg, et. al. Standards Track [Page 126]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ default is 64*T1. However, the client transaction does not know the
+ value of T1 in use by the server transaction, so an absolute minimum
+ of 32s is used instead of basing Timer D on T1.
+
+ Any retransmissions of the final response that are received while in
+ the "Completed" state MUST cause the ACK to be re-passed to the
+ transport layer for retransmission, but the newly received response
+ MUST NOT be passed up to the TU. A retransmission of the response is
+ defined as any response which would match the same client transaction
+ based on the rules of Section 17.1.3.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 127]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ |INVITE from TU
+ Timer A fires |INVITE sent
+ Reset A, V Timer B fires
+ INVITE sent +-----------+ or Transport Err.
+ +---------| |---------------+inform TU
+ | | Calling | |
+ +-------->| |-------------->|
+ +-----------+ 2xx |
+ | | 2xx to TU |
+ | |1xx |
+ 300-699 +---------------+ |1xx to TU |
+ ACK sent | | |
+resp. to TU | 1xx V |
+ | 1xx to TU -----------+ |
+ | +---------| | |
+ | | |Proceeding |-------------->|
+ | +-------->| | 2xx |
+ | +-----------+ 2xx to TU |
+ | 300-699 | |
+ | ACK sent, | |
+ | resp. to TU| |
+ | | | NOTE:
+ | 300-699 V |
+ | ACK sent +-----------+Transport Err. | transitions
+ | +---------| |Inform TU | labeled with
+ | | | Completed |-------------->| the event
+ | +-------->| | | over the action
+ | +-----------+ | to take
+ | ^ | |
+ | | | Timer D fires |
+ +--------------+ | - |
+ | |
+ V |
+ +-----------+ |
+ | | |
+ | Terminated|<--------------+
+ | |
+ +-----------+
+
+ Figure 5: INVITE client transaction
+
+ If timer D fires while the client transaction is in the "Completed"
+ state, the client transaction MUST move to the terminated state.
+
+ When in either the "Calling" or "Proceeding" states, reception of a
+ 2xx response MUST cause the client transaction to enter the
+ "Terminated" state, and the response MUST be passed up to the TU.
+ The handling of this response depends on whether the TU is a proxy
+
+
+
+Rosenberg, et. al. Standards Track [Page 128]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ core or a UAC core. A UAC core will handle generation of the ACK for
+ this response, while a proxy core will always forward the 200 (OK)
+ upstream. The differing treatment of 200 (OK) between proxy and UAC
+ is the reason that handling of it does not take place in the
+ transaction layer.
+
+ The client transaction MUST be destroyed the instant it enters the
+ "Terminated" state. This is actually necessary to guarantee correct
+ operation. The reason is that 2xx responses to an INVITE are treated
+ differently; each one is forwarded by proxies, and the ACK handling
+ in a UAC is different. Thus, each 2xx needs to be passed to a proxy
+ core (so that it can be forwarded) and to a UAC core (so it can be
+ acknowledged). No transaction layer processing takes place.
+ Whenever a response is received by the transport, if the transport
+ layer finds no matching client transaction (using the rules of
+ Section 17.1.3), the response is passed directly to the core. Since
+ the matching client transaction is destroyed by the first 2xx,
+ subsequent 2xx will find no match and therefore be passed to the
+ core.
+
+17.1.1.3 Construction of the ACK Request
+
+ This section specifies the construction of ACK requests sent within
+ the client transaction. A UAC core that generates an ACK for 2xx
+ MUST instead follow the rules described in Section 13.
+
+ The ACK request constructed by the client transaction MUST contain
+ values for the Call-ID, From, and Request-URI that are equal to the
+ values of those header fields in the request passed to the transport
+ by the client transaction (call this the "original request"). The To
+ header field in the ACK MUST equal the To header field in the
+ response being acknowledged, and therefore will usually differ from
+ the To header field in the original request by the addition of the
+ tag parameter. The ACK MUST contain a single Via header field, and
+ this MUST be equal to the top Via header field of the original
+ request. The CSeq header field in the ACK MUST contain the same
+ value for the sequence number as was present in the original request,
+ but the method parameter MUST be equal to "ACK".
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 129]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ If the INVITE request whose response is being acknowledged had Route
+ header fields, those header fields MUST appear in the ACK. This is
+ to ensure that the ACK can be routed properly through any downstream
+ stateless proxies.
+
+ Although any request MAY contain a body, a body in an ACK is special
+ since the request cannot be rejected if the body is not understood.
+ Therefore, placement of bodies in ACK for non-2xx is NOT RECOMMENDED,
+ but if done, the body types are restricted to any that appeared in
+ the INVITE, assuming that the response to the INVITE was not 415. If
+ it was, the body in the ACK MAY be any type listed in the Accept
+ header field in the 415.
+
+ For example, consider the following request:
+
+ INVITE sip:bob@biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
+ To: Bob <sip:bob@biloxi.com>
+ From: Alice <sip:alice@atlanta.com>;tag=88sja8x
+ Max-Forwards: 70
+ Call-ID: 987asjd97y7atg
+ CSeq: 986759 INVITE
+
+ The ACK request for a non-2xx final response to this request would
+ look like this:
+
+ ACK sip:bob@biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
+ To: Bob <sip:bob@biloxi.com>;tag=99sa0xk
+ From: Alice <sip:alice@atlanta.com>;tag=88sja8x
+ Max-Forwards: 70
+ Call-ID: 987asjd97y7atg
+ CSeq: 986759 ACK
+
+17.1.2 Non-INVITE Client Transaction
+
+17.1.2.1 Overview of the non-INVITE Transaction
+
+ Non-INVITE transactions do not make use of ACK. They are simple
+ request-response interactions. For unreliable transports, requests
+ are retransmitted at an interval which starts at T1 and doubles until
+ it hits T2. If a provisional response is received, retransmissions
+ continue for unreliable transports, but at an interval of T2. The
+ server transaction retransmits the last response it sent, which can
+ be a provisional or final response, only when a retransmission of the
+ request is received. This is why request retransmissions need to
+ continue even after a provisional response; they are to ensure
+ reliable delivery of the final response.
+
+
+
+Rosenberg, et. al. Standards Track [Page 130]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Unlike an INVITE transaction, a non-INVITE transaction has no special
+ handling for the 2xx response. The result is that only a single 2xx
+ response to a non-INVITE is ever delivered to a UAC.
+
+17.1.2.2 Formal Description
+
+ The state machine for the non-INVITE client transaction is shown in
+ Figure 6. It is very similar to the state machine for INVITE.
+
+ The "Trying" state is entered when the TU initiates a new client
+ transaction with a request. When entering this state, the client
+ transaction SHOULD set timer F to fire in 64*T1 seconds. The request
+ MUST be passed to the transport layer for transmission. If an
+ unreliable transport is in use, the client transaction MUST set timer
+ E to fire in T1 seconds. If timer E fires while still in this state,
+ the timer is reset, but this time with a value of MIN(2*T1, T2).
+ When the timer fires again, it is reset to a MIN(4*T1, T2). This
+ process continues so that retransmissions occur with an exponentially
+ increasing interval that caps at T2. The default value of T2 is 4s,
+ and it represents the amount of time a non-INVITE server transaction
+ will take to respond to a request, if it does not respond
+ immediately. For the default values of T1 and T2, this results in
+ intervals of 500 ms, 1 s, 2 s, 4 s, 4 s, 4 s, etc.
+
+ If Timer F fires while the client transaction is still in the
+ "Trying" state, the client transaction SHOULD inform the TU about the
+ timeout, and then it SHOULD enter the "Terminated" state. If a
+ provisional response is received while in the "Trying" state, the
+ response MUST be passed to the TU, and then the client transaction
+ SHOULD move to the "Proceeding" state. If a final response (status
+ codes 200-699) is received while in the "Trying" state, the response
+ MUST be passed to the TU, and the client transaction MUST transition
+ to the "Completed" state.
+
+ If Timer E fires while in the "Proceeding" state, the request MUST be
+ passed to the transport layer for retransmission, and Timer E MUST be
+ reset with a value of T2 seconds. If timer F fires while in the
+ "Proceeding" state, the TU MUST be informed of a timeout, and the
+ client transaction MUST transition to the terminated state. If a
+ final response (status codes 200-699) is received while in the
+ "Proceeding" state, the response MUST be passed to the TU, and the
+ client transaction MUST transition to the "Completed" state.
+
+ Once the client transaction enters the "Completed" state, it MUST set
+ Timer K to fire in T4 seconds for unreliable transports, and zero
+ seconds for reliable transports. The "Completed" state exists to
+ buffer any additional response retransmissions that may be received
+ (which is why the client transaction remains there only for
+
+
+
+Rosenberg, et. al. Standards Track [Page 131]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ unreliable transports). T4 represents the amount of time the network
+ will take to clear messages between client and server transactions.
+ The default value of T4 is 5s. A response is a retransmission when
+ it matches the same transaction, using the rules specified in Section
+ 17.1.3. If Timer K fires while in this state, the client transaction
+ MUST transition to the "Terminated" state.
+
+ Once the transaction is in the terminated state, it MUST be destroyed
+ immediately.
+
+17.1.3 Matching Responses to Client Transactions
+
+ When the transport layer in the client receives a response, it has to
+ determine which client transaction will handle the response, so that
+ the processing of Sections 17.1.1 and 17.1.2 can take place. The
+ branch parameter in the top Via header field is used for this
+ purpose. A response matches a client transaction under two
+ conditions:
+
+ 1. If the response has the same value of the branch parameter in
+ the top Via header field as the branch parameter in the top
+ Via header field of the request that created the transaction.
+
+ 2. If the method parameter in the CSeq header field matches the
+ method of the request that created the transaction. The
+ method is needed since a CANCEL request constitutes a
+ different transaction, but shares the same value of the branch
+ parameter.
+
+ If a request is sent via multicast, it is possible that it will
+ generate multiple responses from different servers. These responses
+ will all have the same branch parameter in the topmost Via, but vary
+ in the To tag. The first response received, based on the rules
+ above, will be used, and others will be viewed as retransmissions.
+ That is not an error; multicast SIP provides only a rudimentary
+ "single-hop-discovery-like" service that is limited to processing a
+ single response. See Section 18.1.1 for details.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 132]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+17.1.4 Handling Transport Errors
+
+ |Request from TU
+ |send request
+ Timer E V
+ send request +-----------+
+ +---------| |-------------------+
+ | | Trying | Timer F |
+ +-------->| | or Transport Err.|
+ +-----------+ inform TU |
+ 200-699 | | |
+ resp. to TU | |1xx |
+ +---------------+ |resp. to TU |
+ | | |
+ | Timer E V Timer F |
+ | send req +-----------+ or Transport Err. |
+ | +---------| | inform TU |
+ | | |Proceeding |------------------>|
+ | +-------->| |-----+ |
+ | +-----------+ |1xx |
+ | | ^ |resp to TU |
+ | 200-699 | +--------+ |
+ | resp. to TU | |
+ | | |
+ | V |
+ | +-----------+ |
+ | | | |
+ | | Completed | |
+ | | | |
+ | +-----------+ |
+ | ^ | |
+ | | | Timer K |
+ +--------------+ | - |
+ | |
+ V |
+ NOTE: +-----------+ |
+ | | |
+ transitions | Terminated|<------------------+
+ labeled with | |
+ the event +-----------+
+ over the action
+ to take
+
+ Figure 6: non-INVITE client transaction
+
+ When the client transaction sends a request to the transport layer to
+ be sent, the following procedures are followed if the transport layer
+ indicates a failure.
+
+
+
+Rosenberg, et. al. Standards Track [Page 133]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The client transaction SHOULD inform the TU that a transport failure
+ has occurred, and the client transaction SHOULD transition directly
+ to the "Terminated" state. The TU will handle the failover
+ mechanisms described in [4].
+
+17.2 Server Transaction
+
+ The server transaction is responsible for the delivery of requests to
+ the TU and the reliable transmission of responses. It accomplishes
+ this through a state machine. Server transactions are created by the
+ core when a request is received, and transaction handling is desired
+ for that request (this is not always the case).
+
+ As with the client transactions, the state machine depends on whether
+ the received request is an INVITE request.
+
+17.2.1 INVITE Server Transaction
+
+ The state diagram for the INVITE server transaction is shown in
+ Figure 7.
+
+ When a server transaction is constructed for a request, it enters the
+ "Proceeding" state. The server transaction MUST generate a 100
+ (Trying) response unless it knows that the TU will generate a
+ provisional or final response within 200 ms, in which case it MAY
+ generate a 100 (Trying) response. This provisional response is
+ needed to quench request retransmissions rapidly in order to avoid
+ network congestion. The 100 (Trying) response is constructed
+ according to the procedures in Section 8.2.6, except that the
+ insertion of tags in the To header field of the response (when none
+ was present in the request) is downgraded from MAY to SHOULD NOT.
+ The request MUST be passed to the TU.
+
+ The TU passes any number of provisional responses to the server
+ transaction. So long as the server transaction is in the
+ "Proceeding" state, each of these MUST be passed to the transport
+ layer for transmission. They are not sent reliably by the
+ transaction layer (they are not retransmitted by it) and do not cause
+ a change in the state of the server transaction. If a request
+ retransmission is received while in the "Proceeding" state, the most
+ recent provisional response that was received from the TU MUST be
+ passed to the transport layer for retransmission. A request is a
+ retransmission if it matches the same server transaction based on the
+ rules of Section 17.2.3.
+
+ If, while in the "Proceeding" state, the TU passes a 2xx response to
+ the server transaction, the server transaction MUST pass this
+ response to the transport layer for transmission. It is not
+
+
+
+Rosenberg, et. al. Standards Track [Page 134]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ retransmitted by the server transaction; retransmissions of 2xx
+ responses are handled by the TU. The server transaction MUST then
+ transition to the "Terminated" state.
+
+ While in the "Proceeding" state, if the TU passes a response with
+ status code from 300 to 699 to the server transaction, the response
+ MUST be passed to the transport layer for transmission, and the state
+ machine MUST enter the "Completed" state. For unreliable transports,
+ timer G is set to fire in T1 seconds, and is not set to fire for
+ reliable transports.
+
+ This is a change from RFC 2543, where responses were always
+ retransmitted, even over reliable transports.
+
+ When the "Completed" state is entered, timer H MUST be set to fire in
+ 64*T1 seconds for all transports. Timer H determines when the server
+ transaction abandons retransmitting the response. Its value is
+ chosen to equal Timer B, the amount of time a client transaction will
+ continue to retry sending a request. If timer G fires, the response
+ is passed to the transport layer once more for retransmission, and
+ timer G is set to fire in MIN(2*T1, T2) seconds. From then on, when
+ timer G fires, the response is passed to the transport again for
+ transmission, and timer G is reset with a value that doubles, unless
+ that value exceeds T2, in which case it is reset with the value of
+ T2. This is identical to the retransmit behavior for requests in the
+ "Trying" state of the non-INVITE client transaction. Furthermore,
+ while in the "Completed" state, if a request retransmission is
+ received, the server SHOULD pass the response to the transport for
+ retransmission.
+
+ If an ACK is received while the server transaction is in the
+ "Completed" state, the server transaction MUST transition to the
+ "Confirmed" state. As Timer G is ignored in this state, any
+ retransmissions of the response will cease.
+
+ If timer H fires while in the "Completed" state, it implies that the
+ ACK was never received. In this case, the server transaction MUST
+ transition to the "Terminated" state, and MUST indicate to the TU
+ that a transaction failure has occurred.
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 135]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ |INVITE
+ |pass INV to TU
+ INVITE V send 100 if TU won't in 200ms
+ send response+-----------+
+ +--------| |--------+101-199 from TU
+ | | Proceeding| |send response
+ +------->| |<-------+
+ | | Transport Err.
+ | | Inform TU
+ | |--------------->+
+ +-----------+ |
+ 300-699 from TU | |2xx from TU |
+ send response | |send response |
+ | +------------------>+
+ | |
+ INVITE V Timer G fires |
+ send response+-----------+ send response |
+ +--------| |--------+ |
+ | | Completed | | |
+ +------->| |<-------+ |
+ +-----------+ |
+ | | |
+ ACK | | |
+ - | +------------------>+
+ | Timer H fires |
+ V or Transport Err.|
+ +-----------+ Inform TU |
+ | | |
+ | Confirmed | |
+ | | |
+ +-----------+ |
+ | |
+ |Timer I fires |
+ |- |
+ | |
+ V |
+ +-----------+ |
+ | | |
+ | Terminated|<---------------+
+ | |
+ +-----------+
+
+ Figure 7: INVITE server transaction
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 136]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The purpose of the "Confirmed" state is to absorb any additional ACK
+ messages that arrive, triggered from retransmissions of the final
+ response. When this state is entered, timer I is set to fire in T4
+ seconds for unreliable transports, and zero seconds for reliable
+ transports. Once timer I fires, the server MUST transition to the
+ "Terminated" state.
+
+ Once the transaction is in the "Terminated" state, it MUST be
+ destroyed immediately. As with client transactions, this is needed
+ to ensure reliability of the 2xx responses to INVITE.
+
+17.2.2 Non-INVITE Server Transaction
+
+ The state machine for the non-INVITE server transaction is shown in
+ Figure 8.
+
+ The state machine is initialized in the "Trying" state and is passed
+ a request other than INVITE or ACK when initialized. This request is
+ passed up to the TU. Once in the "Trying" state, any further request
+ retransmissions are discarded. A request is a retransmission if it
+ matches the same server transaction, using the rules specified in
+ Section 17.2.3.
+
+ While in the "Trying" state, if the TU passes a provisional response
+ to the server transaction, the server transaction MUST enter the
+ "Proceeding" state. The response MUST be passed to the transport
+ layer for transmission. Any further provisional responses that are
+ received from the TU while in the "Proceeding" state MUST be passed
+ to the transport layer for transmission. If a retransmission of the
+ request is received while in the "Proceeding" state, the most
+ recently sent provisional response MUST be passed to the transport
+ layer for retransmission. If the TU passes a final response (status
+ codes 200-699) to the server while in the "Proceeding" state, the
+ transaction MUST enter the "Completed" state, and the response MUST
+ be passed to the transport layer for transmission.
+
+ When the server transaction enters the "Completed" state, it MUST set
+ Timer J to fire in 64*T1 seconds for unreliable transports, and zero
+ seconds for reliable transports. While in the "Completed" state, the
+ server transaction MUST pass the final response to the transport
+ layer for retransmission whenever a retransmission of the request is
+ received. Any other final responses passed by the TU to the server
+ transaction MUST be discarded while in the "Completed" state. The
+ server transaction remains in this state until Timer J fires, at
+ which point it MUST transition to the "Terminated" state.
+
+ The server transaction MUST be destroyed the instant it enters the
+ "Terminated" state.
+
+
+
+Rosenberg, et. al. Standards Track [Page 137]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+17.2.3 Matching Requests to Server Transactions
+
+ When a request is received from the network by the server, it has to
+ be matched to an existing transaction. This is accomplished in the
+ following manner.
+
+ The branch parameter in the topmost Via header field of the request
+ is examined. If it is present and begins with the magic cookie
+ "z9hG4bK", the request was generated by a client transaction
+ compliant to this specification. Therefore, the branch parameter
+ will be unique across all transactions sent by that client. The
+ request matches a transaction if:
+
+ 1. the branch parameter in the request is equal to the one in the
+ top Via header field of the request that created the
+ transaction, and
+
+ 2. the sent-by value in the top Via of the request is equal to the
+ one in the request that created the transaction, and
+
+ 3. the method of the request matches the one that created the
+ transaction, except for ACK, where the method of the request
+ that created the transaction is INVITE.
+
+ This matching rule applies to both INVITE and non-INVITE transactions
+ alike.
+
+ The sent-by value is used as part of the matching process because
+ there could be accidental or malicious duplication of branch
+ parameters from different clients.
+
+ If the branch parameter in the top Via header field is not present,
+ or does not contain the magic cookie, the following procedures are
+ used. These exist to handle backwards compatibility with RFC 2543
+ compliant implementations.
+
+ The INVITE request matches a transaction if the Request-URI, To tag,
+ From tag, Call-ID, CSeq, and top Via header field match those of the
+ INVITE request which created the transaction. In this case, the
+ INVITE is a retransmission of the original one that created the
+ transaction. The ACK request matches a transaction if the Request-
+ URI, From tag, Call-ID, CSeq number (not the method), and top Via
+ header field match those of the INVITE request which created the
+ transaction, and the To tag of the ACK matches the To tag of the
+ response sent by the server transaction. Matching is done based on
+ the matching rules defined for each of those header fields.
+ Inclusion of the tag in the To header field in the ACK matching
+ process helps disambiguate ACK for 2xx from ACK for other responses
+
+
+
+Rosenberg, et. al. Standards Track [Page 138]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ at a proxy, which may have forwarded both responses (This can occur
+ in unusual conditions. Specifically, when a proxy forked a request,
+ and then crashes, the responses may be delivered to another proxy,
+ which might end up forwarding multiple responses upstream). An ACK
+ request that matches an INVITE transaction matched by a previous ACK
+ is considered a retransmission of that previous ACK.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 139]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ |Request received
+ |pass to TU
+ V
+ +-----------+
+ | |
+ | Trying |-------------+
+ | | |
+ +-----------+ |200-699 from TU
+ | |send response
+ |1xx from TU |
+ |send response |
+ | |
+ Request V 1xx from TU |
+ send response+-----------+send response|
+ +--------| |--------+ |
+ | | Proceeding| | |
+ +------->| |<-------+ |
+ +<--------------| | |
+ |Trnsprt Err +-----------+ |
+ |Inform TU | |
+ | | |
+ | |200-699 from TU |
+ | |send response |
+ | Request V |
+ | send response+-----------+ |
+ | +--------| | |
+ | | | Completed |<------------+
+ | +------->| |
+ +<--------------| |
+ |Trnsprt Err +-----------+
+ |Inform TU |
+ | |Timer J fires
+ | |-
+ | |
+ | V
+ | +-----------+
+ | | |
+ +-------------->| Terminated|
+ | |
+ +-----------+
+
+ Figure 8: non-INVITE server transaction
+
+ For all other request methods, a request is matched to a transaction
+ if the Request-URI, To tag, From tag, Call-ID, CSeq (including the
+ method), and top Via header field match those of the request that
+ created the transaction. Matching is done based on the matching
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 140]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ rules defined for each of those header fields. When a non-INVITE
+ request matches an existing transaction, it is a retransmission of
+ the request that created that transaction.
+
+ Because the matching rules include the Request-URI, the server cannot
+ match a response to a transaction. When the TU passes a response to
+ the server transaction, it must pass it to the specific server
+ transaction for which the response is targeted.
+
+17.2.4 Handling Transport Errors
+
+ When the server transaction sends a response to the transport layer
+ to be sent, the following procedures are followed if the transport
+ layer indicates a failure.
+
+ First, the procedures in [4] are followed, which attempt to deliver
+ the response to a backup. If those should all fail, based on the
+ definition of failure in [4], the server transaction SHOULD inform
+ the TU that a failure has occurred, and SHOULD transition to the
+ terminated state.
+
+18 Transport
+
+ The transport layer is responsible for the actual transmission of
+ requests and responses over network transports. This includes
+ determination of the connection to use for a request or response in
+ the case of connection-oriented transports.
+
+ The transport layer is responsible for managing persistent
+ connections for transport protocols like TCP and SCTP, or TLS over
+ those, including ones opened to the transport layer. This includes
+ connections opened by the client or server transports, so that
+ connections are shared between client and server transport functions.
+ These connections are indexed by the tuple formed from the address,
+ port, and transport protocol at the far end of the connection. When
+ a connection is opened by the transport layer, this index is set to
+ the destination IP, port and transport. When the connection is
+ accepted by the transport layer, this index is set to the source IP
+ address, port number, and transport. Note that, because the source
+ port is often ephemeral, but it cannot be known whether it is
+ ephemeral or selected through procedures in [4], connections accepted
+ by the transport layer will frequently not be reused. The result is
+ that two proxies in a "peering" relationship using a connection-
+ oriented transport frequently will have two connections in use, one
+ for transactions initiated in each direction.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 141]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ It is RECOMMENDED that connections be kept open for some
+ implementation-defined duration after the last message was sent or
+ received over that connection. This duration SHOULD at least equal
+ the longest amount of time the element would need in order to bring a
+ transaction from instantiation to the terminated state. This is to
+ make it likely that transactions are completed over the same
+ connection on which they are initiated (for example, request,
+ response, and in the case of INVITE, ACK for non-2xx responses).
+ This usually means at least 64*T1 (see Section 17.1.1.1 for a
+ definition of T1). However, it could be larger in an element that
+ has a TU using a large value for timer C (bullet 11 of Section 16.6),
+ for example.
+
+ All SIP elements MUST implement UDP and TCP. SIP elements MAY
+ implement other protocols.
+
+ Making TCP mandatory for the UA is a substantial change from RFC
+ 2543. It has arisen out of the need to handle larger messages,
+ which MUST use TCP, as discussed below. Thus, even if an element
+ never sends large messages, it may receive one and needs to be
+ able to handle them.
+
+18.1 Clients
+
+18.1.1 Sending Requests
+
+ The client side of the transport layer is responsible for sending the
+ request and receiving responses. The user of the transport layer
+ passes the client transport the request, an IP address, port,
+ transport, and possibly TTL for multicast destinations.
+
+ If a request is within 200 bytes of the path MTU, or if it is larger
+ than 1300 bytes and the path MTU is unknown, the request MUST be sent
+ using an RFC 2914 [43] congestion controlled transport protocol, such
+ as TCP. If this causes a change in the transport protocol from the
+ one indicated in the top Via, the value in the top Via MUST be
+ changed. This prevents fragmentation of messages over UDP and
+ provides congestion control for larger messages. However,
+ implementations MUST be able to handle messages up to the maximum
+ datagram packet size. For UDP, this size is 65,535 bytes, including
+ IP and UDP headers.
+
+ The 200 byte "buffer" between the message size and the MTU
+ accommodates the fact that the response in SIP can be larger than
+ the request. This happens due to the addition of Record-Route
+ header field values to the responses to INVITE, for example. With
+ the extra buffer, the response can be about 170 bytes larger than
+ the request, and still not be fragmented on IPv4 (about 30 bytes
+
+
+
+Rosenberg, et. al. Standards Track [Page 142]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ is consumed by IP/UDP, assuming no IPSec). 1300 is chosen when
+ path MTU is not known, based on the assumption of a 1500 byte
+ Ethernet MTU.
+
+ If an element sends a request over TCP because of these message size
+ constraints, and that request would have otherwise been sent over
+ UDP, if the attempt to establish the connection generates either an
+ ICMP Protocol Not Supported, or results in a TCP reset, the element
+ SHOULD retry the request, using UDP. This is only to provide
+ backwards compatibility with RFC 2543 compliant implementations that
+ do not support TCP. It is anticipated that this behavior will be
+ deprecated in a future revision of this specification.
+
+ A client that sends a request to a multicast address MUST add the
+ "maddr" parameter to its Via header field value containing the
+ destination multicast address, and for IPv4, SHOULD add the "ttl"
+ parameter with a value of 1. Usage of IPv6 multicast is not defined
+ in this specification, and will be a subject of future
+ standardization when the need arises.
+
+ These rules result in a purposeful limitation of multicast in SIP.
+ Its primary function is to provide a "single-hop-discovery-like"
+ service, delivering a request to a group of homogeneous servers,
+ where it is only required to process the response from any one of
+ them. This functionality is most useful for registrations. In fact,
+ based on the transaction processing rules in Section 17.1.3, the
+ client transaction will accept the first response, and view any
+ others as retransmissions because they all contain the same Via
+ branch identifier.
+
+ Before a request is sent, the client transport MUST insert a value of
+ the "sent-by" field into the Via header field. This field contains
+ an IP address or host name, and port. The usage of an FQDN is
+ RECOMMENDED. This field is used for sending responses under certain
+ conditions, described below. If the port is absent, the default
+ value depends on the transport. It is 5060 for UDP, TCP and SCTP,
+ 5061 for TLS.
+
+ For reliable transports, the response is normally sent on the
+ connection on which the request was received. Therefore, the client
+ transport MUST be prepared to receive the response on the same
+ connection used to send the request. Under error conditions, the
+ server may attempt to open a new connection to send the response. To
+ handle this case, the transport layer MUST also be prepared to
+ receive an incoming connection on the source IP address from which
+ the request was sent and port number in the "sent-by" field. It also
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 143]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ MUST be prepared to receive incoming connections on any address and
+ port that would be selected by a server based on the procedures
+ described in Section 5 of [4].
+
+ For unreliable unicast transports, the client transport MUST be
+ prepared to receive responses on the source IP address from which the
+ request is sent (as responses are sent back to the source address)
+ and the port number in the "sent-by" field. Furthermore, as with
+ reliable transports, in certain cases the response will be sent
+ elsewhere. The client MUST be prepared to receive responses on any
+ address and port that would be selected by a server based on the
+ procedures described in Section 5 of [4].
+
+ For multicast, the client transport MUST be prepared to receive
+ responses on the same multicast group and port to which the request
+ is sent (that is, it needs to be a member of the multicast group it
+ sent the request to.)
+
+ If a request is destined to an IP address, port, and transport to
+ which an existing connection is open, it is RECOMMENDED that this
+ connection be used to send the request, but another connection MAY be
+ opened and used.
+
+ If a request is sent using multicast, it is sent to the group
+ address, port, and TTL provided by the transport user. If a request
+ is sent using unicast unreliable transports, it is sent to the IP
+ address and port provided by the transport user.
+
+18.1.2 Receiving Responses
+
+ When a response is received, the client transport examines the top
+ Via header field value. If the value of the "sent-by" parameter in
+ that header field value does not correspond to a value that the
+ client transport is configured to insert into requests, the response
+ MUST be silently discarded.
+
+ If there are any client transactions in existence, the client
+ transport uses the matching procedures of Section 17.1.3 to attempt
+ to match the response to an existing transaction. If there is a
+ match, the response MUST be passed to that transaction. Otherwise,
+ the response MUST be passed to the core (whether it be stateless
+ proxy, stateful proxy, or UA) for further processing. Handling of
+ these "stray" responses is dependent on the core (a proxy will
+ forward them, while a UA will discard, for example).
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 144]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+18.2 Servers
+
+18.2.1 Receiving Requests
+
+ A server SHOULD be prepared to receive requests on any IP address,
+ port and transport combination that can be the result of a DNS lookup
+ on a SIP or SIPS URI [4] that is handed out for the purposes of
+ communicating with that server. In this context, "handing out"
+ includes placing a URI in a Contact header field in a REGISTER
+ request or a redirect response, or in a Record-Route header field in
+ a request or response. A URI can also be "handed out" by placing it
+ on a web page or business card. It is also RECOMMENDED that a server
+ listen for requests on the default SIP ports (5060 for TCP and UDP,
+ 5061 for TLS over TCP) on all public interfaces. The typical
+ exception would be private networks, or when multiple server
+ instances are running on the same host. For any port and interface
+ that a server listens on for UDP, it MUST listen on that same port
+ and interface for TCP. This is because a message may need to be sent
+ using TCP, rather than UDP, if it is too large. As a result, the
+ converse is not true. A server need not listen for UDP on a
+ particular address and port just because it is listening on that same
+ address and port for TCP. There may, of course, be other reasons why
+ a server needs to listen for UDP on a particular address and port.
+
+ When the server transport receives a request over any transport, it
+ MUST examine the value of the "sent-by" parameter in the top Via
+ header field value. If the host portion of the "sent-by" parameter
+ contains a domain name, or if it contains an IP address that differs
+ from the packet source address, the server MUST add a "received"
+ parameter to that Via header field value. This parameter MUST
+ contain the source address from which the packet was received. This
+ is to assist the server transport layer in sending the response,
+ since it must be sent to the source IP address from which the request
+ came.
+
+ Consider a request received by the server transport which looks like,
+ in part:
+
+ INVITE sip:bob@Biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP bobspc.biloxi.com:5060
+
+ The request is received with a source IP address of 192.0.2.4.
+ Before passing the request up, the transport adds a "received"
+ parameter, so that the request would look like, in part:
+
+ INVITE sip:bob@Biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP bobspc.biloxi.com:5060;received=192.0.2.4
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 145]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Next, the server transport attempts to match the request to a server
+ transaction. It does so using the matching rules described in
+ Section 17.2.3. If a matching server transaction is found, the
+ request is passed to that transaction for processing. If no match is
+ found, the request is passed to the core, which may decide to
+ construct a new server transaction for that request. Note that when
+ a UAS core sends a 2xx response to INVITE, the server transaction is
+ destroyed. This means that when the ACK arrives, there will be no
+ matching server transaction, and based on this rule, the ACK is
+ passed to the UAS core, where it is processed.
+
+18.2.2 Sending Responses
+
+ The server transport uses the value of the top Via header field in
+ order to determine where to send a response. It MUST follow the
+ following process:
+
+ o If the "sent-protocol" is a reliable transport protocol such as
+ TCP or SCTP, or TLS over those, the response MUST be sent using
+ the existing connection to the source of the original request
+ that created the transaction, if that connection is still open.
+ This requires the server transport to maintain an association
+ between server transactions and transport connections. If that
+ connection is no longer open, the server SHOULD open a
+ connection to the IP address in the "received" parameter, if
+ present, using the port in the "sent-by" value, or the default
+ port for that transport, if no port is specified. If that
+ connection attempt fails, the server SHOULD use the procedures
+ in [4] for servers in order to determine the IP address and
+ port to open the connection and send the response to.
+
+ o Otherwise, if the Via header field value contains a "maddr"
+ parameter, the response MUST be forwarded to the address listed
+ there, using the port indicated in "sent-by", or port 5060 if
+ none is present. If the address is a multicast address, the
+ response SHOULD be sent using the TTL indicated in the "ttl"
+ parameter, or with a TTL of 1 if that parameter is not present.
+
+ o Otherwise (for unreliable unicast transports), if the top Via
+ has a "received" parameter, the response MUST be sent to the
+ address in the "received" parameter, using the port indicated
+ in the "sent-by" value, or using port 5060 if none is specified
+ explicitly. If this fails, for example, elicits an ICMP "port
+ unreachable" response, the procedures of Section 5 of [4]
+ SHOULD be used to determine where to send the response.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 146]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o Otherwise, if it is not receiver-tagged, the response MUST be
+ sent to the address indicated by the "sent-by" value, using the
+ procedures in Section 5 of [4].
+
+18.3 Framing
+
+ In the case of message-oriented transports (such as UDP), if the
+ message has a Content-Length header field, the message body is
+ assumed to contain that many bytes. If there are additional bytes in
+ the transport packet beyond the end of the body, they MUST be
+ discarded. If the transport packet ends before the end of the
+ message body, this is considered an error. If the message is a
+ response, it MUST be discarded. If the message is a request, the
+ element SHOULD generate a 400 (Bad Request) response. If the message
+ has no Content-Length header field, the message body is assumed to
+ end at the end of the transport packet.
+
+ In the case of stream-oriented transports such as TCP, the Content-
+ Length header field indicates the size of the body. The Content-
+ Length header field MUST be used with stream oriented transports.
+
+18.4 Error Handling
+
+ Error handling is independent of whether the message was a request or
+ response.
+
+ If the transport user asks for a message to be sent over an
+ unreliable transport, and the result is an ICMP error, the behavior
+ depends on the type of ICMP error. Host, network, port or protocol
+ unreachable errors, or parameter problem errors SHOULD cause the
+ transport layer to inform the transport user of a failure in sending.
+ Source quench and TTL exceeded ICMP errors SHOULD be ignored.
+
+ If the transport user asks for a request to be sent over a reliable
+ transport, and the result is a connection failure, the transport
+ layer SHOULD inform the transport user of a failure in sending.
+
+19 Common Message Components
+
+ There are certain components of SIP messages that appear in various
+ places within SIP messages (and sometimes, outside of them) that
+ merit separate discussion.
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 147]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+19.1 SIP and SIPS Uniform Resource Indicators
+
+ A SIP or SIPS URI identifies a communications resource. Like all
+ URIs, SIP and SIPS URIs may be placed in web pages, email messages,
+ or printed literature. They contain sufficient information to
+ initiate and maintain a communication session with the resource.
+
+ Examples of communications resources include the following:
+
+ o a user of an online service
+
+ o an appearance on a multi-line phone
+
+ o a mailbox on a messaging system
+
+ o a PSTN number at a gateway service
+
+ o a group (such as "sales" or "helpdesk") in an organization
+
+ A SIPS URI specifies that the resource be contacted securely. This
+ means, in particular, that TLS is to be used between the UAC and the
+ domain that owns the URI. From there, secure communications are used
+ to reach the user, where the specific security mechanism depends on
+ the policy of the domain. Any resource described by a SIP URI can be
+ "upgraded" to a SIPS URI by just changing the scheme, if it is
+ desired to communicate with that resource securely.
+
+19.1.1 SIP and SIPS URI Components
+
+ The "sip:" and "sips:" schemes follow the guidelines in RFC 2396 [5].
+ They use a form similar to the mailto URL, allowing the specification
+ of SIP request-header fields and the SIP message-body. This makes it
+ possible to specify the subject, media type, or urgency of sessions
+ initiated by using a URI on a web page or in an email message. The
+ formal syntax for a SIP or SIPS URI is presented in Section 25. Its
+ general form, in the case of a SIP URI, is:
+
+ sip:user:password@host:port;uri-parameters?headers
+
+ The format for a SIPS URI is the same, except that the scheme is
+ "sips" instead of sip. These tokens, and some of the tokens in their
+ expansions, have the following meanings:
+
+ user: The identifier of a particular resource at the host being
+ addressed. The term "host" in this context frequently refers
+ to a domain. The "userinfo" of a URI consists of this user
+ field, the password field, and the @ sign following them. The
+ userinfo part of a URI is optional and MAY be absent when the
+
+
+
+Rosenberg, et. al. Standards Track [Page 148]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ destination host does not have a notion of users or when the
+ host itself is the resource being identified. If the @ sign is
+ present in a SIP or SIPS URI, the user field MUST NOT be empty.
+
+ If the host being addressed can process telephone numbers, for
+ instance, an Internet telephony gateway, a telephone-
+ subscriber field defined in RFC 2806 [9] MAY be used to
+ populate the user field. There are special escaping rules for
+ encoding telephone-subscriber fields in SIP and SIPS URIs
+ described in Section 19.1.2.
+
+ password: A password associated with the user. While the SIP and
+ SIPS URI syntax allows this field to be present, its use is NOT
+ RECOMMENDED, because the passing of authentication information
+ in clear text (such as URIs) has proven to be a security risk
+ in almost every case where it has been used. For instance,
+ transporting a PIN number in this field exposes the PIN.
+
+ Note that the password field is just an extension of the user
+ portion. Implementations not wishing to give special
+ significance to the password portion of the field MAY simply
+ treat "user:password" as a single string.
+
+ host: The host providing the SIP resource. The host part contains
+ either a fully-qualified domain name or numeric IPv4 or IPv6
+ address. Using the fully-qualified domain name form is
+ RECOMMENDED whenever possible.
+
+ port: The port number where the request is to be sent.
+
+ URI parameters: Parameters affecting a request constructed from
+ the URI.
+
+ URI parameters are added after the hostport component and are
+ separated by semi-colons.
+
+ URI parameters take the form:
+
+ parameter-name "=" parameter-value
+
+ Even though an arbitrary number of URI parameters may be
+ included in a URI, any given parameter-name MUST NOT appear
+ more than once.
+
+ This extensible mechanism includes the transport, maddr, ttl,
+ user, method and lr parameters.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 149]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The transport parameter determines the transport mechanism to
+ be used for sending SIP messages, as specified in [4]. SIP can
+ use any network transport protocol. Parameter names are
+ defined for UDP (RFC 768 [14]), TCP (RFC 761 [15]), and SCTP
+ (RFC 2960 [16]). For a SIPS URI, the transport parameter MUST
+ indicate a reliable transport.
+
+ The maddr parameter indicates the server address to be
+ contacted for this user, overriding any address derived from
+ the host field. When an maddr parameter is present, the port
+ and transport components of the URI apply to the address
+ indicated in the maddr parameter value. [4] describes the
+ proper interpretation of the transport, maddr, and hostport in
+ order to obtain the destination address, port, and transport
+ for sending a request.
+
+ The maddr field has been used as a simple form of loose source
+ routing. It allows a URI to specify a proxy that must be
+ traversed en-route to the destination. Continuing to use the
+ maddr parameter this way is strongly discouraged (the
+ mechanisms that enable it are deprecated). Implementations
+ should instead use the Route mechanism described in this
+ document, establishing a pre-existing route set if necessary
+ (see Section 8.1.1.1). This provides a full URI to describe
+ the node to be traversed.
+
+ The ttl parameter determines the time-to-live value of the UDP
+ multicast packet and MUST only be used if maddr is a multicast
+ address and the transport protocol is UDP. For example, to
+ specify a call to alice@atlanta.com using multicast to
+ 239.255.255.1 with a ttl of 15, the following URI would be
+ used:
+
+ sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15
+
+ The set of valid telephone-subscriber strings is a subset of
+ valid user strings. The user URI parameter exists to
+ distinguish telephone numbers from user names that happen to
+ look like telephone numbers. If the user string contains a
+ telephone number formatted as a telephone-subscriber, the user
+ parameter value "phone" SHOULD be present. Even without this
+ parameter, recipients of SIP and SIPS URIs MAY interpret the
+ pre-@ part as a telephone number if local restrictions on the
+ name space for user name allow it.
+
+ The method of the SIP request constructed from the URI can be
+ specified with the method parameter.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 150]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The lr parameter, when present, indicates that the element
+ responsible for this resource implements the routing mechanisms
+ specified in this document. This parameter will be used in the
+ URIs proxies place into Record-Route header field values, and
+ may appear in the URIs in a pre-existing route set.
+
+ This parameter is used to achieve backwards compatibility with
+ systems implementing the strict-routing mechanisms of RFC 2543
+ and the rfc2543bis drafts up to bis-05. An element preparing
+ to send a request based on a URI not containing this parameter
+ can assume the receiving element implements strict-routing and
+ reformat the message to preserve the information in the
+ Request-URI.
+
+ Since the uri-parameter mechanism is extensible, SIP elements
+ MUST silently ignore any uri-parameters that they do not
+ understand.
+
+ Headers: Header fields to be included in a request constructed
+ from the URI.
+
+ Headers fields in the SIP request can be specified with the "?"
+ mechanism within a URI. The header names and values are
+ encoded in ampersand separated hname = hvalue pairs. The
+ special hname "body" indicates that the associated hvalue is
+ the message-body of the SIP request.
+
+ Table 1 summarizes the use of SIP and SIPS URI components based on
+ the context in which the URI appears. The external column describes
+ URIs appearing anywhere outside of a SIP message, for instance on a
+ web page or business card. Entries marked "m" are mandatory, those
+ marked "o" are optional, and those marked "-" are not allowed.
+ Elements processing URIs SHOULD ignore any disallowed components if
+ they are present. The second column indicates the default value of
+ an optional element if it is not present. "--" indicates that the
+ element is either not optional, or has no default value.
+
+ URIs in Contact header fields have different restrictions depending
+ on the context in which the header field appears. One set applies to
+ messages that establish and maintain dialogs (INVITE and its 200 (OK)
+ response). The other applies to registration and redirection
+ messages (REGISTER, its 200 (OK) response, and 3xx class responses to
+ any method).
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 151]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+19.1.2 Character Escaping Requirements
+
+ dialog
+ reg./redir. Contact/
+ default Req.-URI To From Contact R-R/Route external
+user -- o o o o o o
+password -- o o o o o o
+host -- m m m m m m
+port (1) o - - o o o
+user-param ip o o o o o o
+method INVITE - - - - - o
+maddr-param -- o - - o o o
+ttl-param 1 o - - o - o
+transp.-param (2) o - - o o o
+lr-param -- o - - - o o
+other-param -- o o o o o o
+headers -- - - - o - o
+
+ (1): The default port value is transport and scheme dependent. The
+ default is 5060 for sip: using UDP, TCP, or SCTP. The default is
+ 5061 for sip: using TLS over TCP and sips: over TCP.
+
+ (2): The default transport is scheme dependent. For sip:, it is UDP.
+ For sips:, it is TCP.
+
+ Table 1: Use and default values of URI components for SIP header
+ field values, Request-URI and references
+
+ SIP follows the requirements and guidelines of RFC 2396 [5] when
+ defining the set of characters that must be escaped in a SIP URI, and
+ uses its ""%" HEX HEX" mechanism for escaping. From RFC 2396 [5]:
+
+ The set of characters actually reserved within any given URI
+ component is defined by that component. In general, a character
+ is reserved if the semantics of the URI changes if the character
+ is replaced with its escaped US-ASCII encoding [5]. Excluded US-
+ ASCII characters (RFC 2396 [5]), such as space and control
+ characters and characters used as URI delimiters, also MUST be
+ escaped. URIs MUST NOT contain unescaped space and control
+ characters.
+
+ For each component, the set of valid BNF expansions defines exactly
+ which characters may appear unescaped. All other characters MUST be
+ escaped.
+
+ For example, "@" is not in the set of characters in the user
+ component, so the user "j@s0n" must have at least the @ sign encoded,
+ as in "j%40s0n".
+
+
+
+Rosenberg, et. al. Standards Track [Page 152]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Expanding the hname and hvalue tokens in Section 25 show that all URI
+ reserved characters in header field names and values MUST be escaped.
+
+ The telephone-subscriber subset of the user component has special
+ escaping considerations. The set of characters not reserved in the
+ RFC 2806 [9] description of telephone-subscriber contains a number of
+ characters in various syntax elements that need to be escaped when
+ used in SIP URIs. Any characters occurring in a telephone-subscriber
+ that do not appear in an expansion of the BNF for the user rule MUST
+ be escaped.
+
+ Note that character escaping is not allowed in the host component of
+ a SIP or SIPS URI (the % character is not valid in its expansion).
+ This is likely to change in the future as requirements for
+ Internationalized Domain Names are finalized. Current
+ implementations MUST NOT attempt to improve robustness by treating
+ received escaped characters in the host component as literally
+ equivalent to their unescaped counterpart. The behavior required to
+ meet the requirements of IDN may be significantly different.
+
+19.1.3 Example SIP and SIPS URIs
+
+ sip:alice@atlanta.com
+ sip:alice:secretword@atlanta.com;transport=tcp
+ sips:alice@atlanta.com?subject=project%20x&priority=urgent
+ sip:+1-212-555-1212:1234@gateway.com;user=phone
+ sips:1212@gateway.com
+ sip:alice@192.0.2.4
+ sip:atlanta.com;method=REGISTER?to=alice%40atlanta.com
+ sip:alice;day=tuesday@atlanta.com
+
+ The last sample URI above has a user field value of
+ "alice;day=tuesday". The escaping rules defined above allow a
+ semicolon to appear unescaped in this field. For the purposes of
+ this protocol, the field is opaque. The structure of that value is
+ only useful to the SIP element responsible for the resource.
+
+19.1.4 URI Comparison
+
+ Some operations in this specification require determining whether two
+ SIP or SIPS URIs are equivalent. In this specification, registrars
+ need to compare bindings in Contact URIs in REGISTER requests (see
+ Section 10.3.). SIP and SIPS URIs are compared for equality
+ according to the following rules:
+
+ o A SIP and SIPS URI are never equivalent.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 153]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o Comparison of the userinfo of SIP and SIPS URIs is case-
+ sensitive. This includes userinfo containing passwords or
+ formatted as telephone-subscribers. Comparison of all other
+ components of the URI is case-insensitive unless explicitly
+ defined otherwise.
+
+ o The ordering of parameters and header fields is not significant
+ in comparing SIP and SIPS URIs.
+
+ o Characters other than those in the "reserved" set (see RFC 2396
+ [5]) are equivalent to their ""%" HEX HEX" encoding.
+
+ o An IP address that is the result of a DNS lookup of a host name
+ does not match that host name.
+
+ o For two URIs to be equal, the user, password, host, and port
+ components must match.
+
+ A URI omitting the user component will not match a URI that
+ includes one. A URI omitting the password component will not
+ match a URI that includes one.
+
+ A URI omitting any component with a default value will not
+ match a URI explicitly containing that component with its
+ default value. For instance, a URI omitting the optional port
+ component will not match a URI explicitly declaring port 5060.
+ The same is true for the transport-parameter, ttl-parameter,
+ user-parameter, and method components.
+
+ Defining sip:user@host to not be equivalent to
+ sip:user@host:5060 is a change from RFC 2543. When deriving
+ addresses from URIs, equivalent addresses are expected from
+ equivalent URIs. The URI sip:user@host:5060 will always
+ resolve to port 5060. The URI sip:user@host may resolve to
+ other ports through the DNS SRV mechanisms detailed in [4].
+
+ o URI uri-parameter components are compared as follows:
+
+ - Any uri-parameter appearing in both URIs must match.
+
+ - A user, ttl, or method uri-parameter appearing in only one
+ URI never matches, even if it contains the default value.
+
+ - A URI that includes an maddr parameter will not match a URI
+ that contains no maddr parameter.
+
+ - All other uri-parameters appearing in only one URI are
+ ignored when comparing the URIs.
+
+
+
+Rosenberg, et. al. Standards Track [Page 154]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o URI header components are never ignored. Any present header
+ component MUST be present in both URIs and match for the URIs
+ to match. The matching rules are defined for each header field
+ in Section 20.
+
+ The URIs within each of the following sets are equivalent:
+
+ sip:%61lice@atlanta.com;transport=TCP
+ sip:alice@AtLanTa.CoM;Transport=tcp
+
+ sip:carol@chicago.com
+ sip:carol@chicago.com;newparam=5
+ sip:carol@chicago.com;security=on
+
+ sip:biloxi.com;transport=tcp;method=REGISTER?to=sip:bob%40biloxi.com
+ sip:biloxi.com;method=REGISTER;transport=tcp?to=sip:bob%40biloxi.com
+
+ sip:alice@atlanta.com?subject=project%20x&priority=urgent
+ sip:alice@atlanta.com?priority=urgent&subject=project%20x
+
+ The URIs within each of the following sets are not equivalent:
+
+ SIP:ALICE@AtLanTa.CoM;Transport=udp (different usernames)
+ sip:alice@AtLanTa.CoM;Transport=UDP
+
+ sip:bob@biloxi.com (can resolve to different ports)
+ sip:bob@biloxi.com:5060
+
+ sip:bob@biloxi.com (can resolve to different transports)
+ sip:bob@biloxi.com;transport=udp
+
+ sip:bob@biloxi.com (can resolve to different port and transports)
+ sip:bob@biloxi.com:6000;transport=tcp
+
+ sip:carol@chicago.com (different header component)
+ sip:carol@chicago.com?Subject=next%20meeting
+
+ sip:bob@phone21.boxesbybob.com (even though that's what
+ sip:bob@192.0.2.4 phone21.boxesbybob.com resolves to)
+
+ Note that equality is not transitive:
+
+ o sip:carol@chicago.com and sip:carol@chicago.com;security=on are
+ equivalent
+
+ o sip:carol@chicago.com and sip:carol@chicago.com;security=off
+ are equivalent
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 155]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o sip:carol@chicago.com;security=on and
+ sip:carol@chicago.com;security=off are not equivalent
+
+19.1.5 Forming Requests from a URI
+
+ An implementation needs to take care when forming requests directly
+ from a URI. URIs from business cards, web pages, and even from
+ sources inside the protocol such as registered contacts may contain
+ inappropriate header fields or body parts.
+
+ An implementation MUST include any provided transport, maddr, ttl, or
+ user parameter in the Request-URI of the formed request. If the URI
+ contains a method parameter, its value MUST be used as the method of
+ the request. The method parameter MUST NOT be placed in the
+ Request-URI. Unknown URI parameters MUST be placed in the message's
+ Request-URI.
+
+ An implementation SHOULD treat the presence of any headers or body
+ parts in the URI as a desire to include them in the message, and
+ choose to honor the request on a per-component basis.
+
+ An implementation SHOULD NOT honor these obviously dangerous header
+ fields: From, Call-ID, CSeq, Via, and Record-Route.
+
+ An implementation SHOULD NOT honor any requested Route header field
+ values in order to not be used as an unwitting agent in malicious
+ attacks.
+
+ An implementation SHOULD NOT honor requests to include header fields
+ that may cause it to falsely advertise its location or capabilities.
+ These include: Accept, Accept-Encoding, Accept-Language, Allow,
+ Contact (in its dialog usage), Organization, Supported, and User-
+ Agent.
+
+ An implementation SHOULD verify the accuracy of any requested
+ descriptive header fields, including: Content-Disposition, Content-
+ Encoding, Content-Language, Content-Length, Content-Type, Date,
+ Mime-Version, and Timestamp.
+
+ If the request formed from constructing a message from a given URI is
+ not a valid SIP request, the URI is invalid. An implementation MUST
+ NOT proceed with transmitting the request. It should instead pursue
+ the course of action due an invalid URI in the context it occurs.
+
+ The constructed request can be invalid in many ways. These
+ include, but are not limited to, syntax error in header fields,
+ invalid combinations of URI parameters, or an incorrect
+ description of the message body.
+
+
+
+Rosenberg, et. al. Standards Track [Page 156]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Sending a request formed from a given URI may require capabilities
+ unavailable to the implementation. The URI might indicate use of an
+ unimplemented transport or extension, for example. An implementation
+ SHOULD refuse to send these requests rather than modifying them to
+ match their capabilities. An implementation MUST NOT send a request
+ requiring an extension that it does not support.
+
+ For example, such a request can be formed through the presence of
+ a Require header parameter or a method URI parameter with an
+ unknown or explicitly unsupported value.
+
+19.1.6 Relating SIP URIs and tel URLs
+
+ When a tel URL (RFC 2806 [9]) is converted to a SIP or SIPS URI, the
+ entire telephone-subscriber portion of the tel URL, including any
+ parameters, is placed into the userinfo part of the SIP or SIPS URI.
+
+ Thus, tel:+358-555-1234567;postd=pp22 becomes
+
+ sip:+358-555-1234567;postd=pp22@foo.com;user=phone
+
+ or
+ sips:+358-555-1234567;postd=pp22@foo.com;user=phone
+
+ not
+ sip:+358-555-1234567@foo.com;postd=pp22;user=phone
+
+ or
+
+ sips:+358-555-1234567@foo.com;postd=pp22;user=phone
+
+ In general, equivalent "tel" URLs converted to SIP or SIPS URIs in
+ this fashion may not produce equivalent SIP or SIPS URIs. The
+ userinfo of SIP and SIPS URIs are compared as a case-sensitive
+ string. Variance in case-insensitive portions of tel URLs and
+ reordering of tel URL parameters does not affect tel URL equivalence,
+ but does affect the equivalence of SIP URIs formed from them.
+
+ For example,
+
+ tel:+358-555-1234567;postd=pp22
+ tel:+358-555-1234567;POSTD=PP22
+
+ are equivalent, while
+
+ sip:+358-555-1234567;postd=pp22@foo.com;user=phone
+ sip:+358-555-1234567;POSTD=PP22@foo.com;user=phone
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 157]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ are not.
+
+ Likewise,
+
+ tel:+358-555-1234567;postd=pp22;isub=1411
+ tel:+358-555-1234567;isub=1411;postd=pp22
+
+ are equivalent, while
+
+ sip:+358-555-1234567;postd=pp22;isub=1411@foo.com;user=phone
+ sip:+358-555-1234567;isub=1411;postd=pp22@foo.com;user=phone
+
+ are not.
+
+ To mitigate this problem, elements constructing telephone-subscriber
+ fields to place in the userinfo part of a SIP or SIPS URI SHOULD fold
+ any case-insensitive portion of telephone-subscriber to lower case,
+ and order the telephone-subscriber parameters lexically by parameter
+ name, excepting isdn-subaddress and post-dial, which occur first and
+ in that order. (All components of a tel URL except for future-
+ extension parameters are defined to be compared case-insensitive.)
+
+ Following this suggestion, both
+
+ tel:+358-555-1234567;postd=pp22
+ tel:+358-555-1234567;POSTD=PP22
+
+ become
+
+ sip:+358-555-1234567;postd=pp22@foo.com;user=phone
+
+ and both
+
+ tel:+358-555-1234567;tsp=a.b;phone-context=5
+ tel:+358-555-1234567;phone-context=5;tsp=a.b
+
+ become
+
+ sip:+358-555-1234567;phone-context=5;tsp=a.b@foo.com;user=phone
+
+19.2 Option Tags
+
+ Option tags are unique identifiers used to designate new options
+ (extensions) in SIP. These tags are used in Require (Section 20.32),
+ Proxy-Require (Section 20.29), Supported (Section 20.37) and
+ Unsupported (Section 20.40) header fields. Note that these options
+ appear as parameters in those header fields in an option-tag = token
+ form (see Section 25 for the definition of token).
+
+
+
+Rosenberg, et. al. Standards Track [Page 158]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Option tags are defined in standards track RFCs. This is a change
+ from past practice, and is instituted to ensure continuing multi-
+ vendor interoperability (see discussion in Section 20.32 and Section
+ 20.37). An IANA registry of option tags is used to ensure easy
+ reference.
+
+19.3 Tags
+
+ The "tag" parameter is used in the To and From header fields of SIP
+ messages. It serves as a general mechanism to identify a dialog,
+ which is the combination of the Call-ID along with two tags, one from
+ each participant in the dialog. When a UA sends a request outside of
+ a dialog, it contains a From tag only, providing "half" of the dialog
+ ID. The dialog is completed from the response(s), each of which
+ contributes the second half in the To header field. The forking of
+ SIP requests means that multiple dialogs can be established from a
+ single request. This also explains the need for the two-sided dialog
+ identifier; without a contribution from the recipients, the
+ originator could not disambiguate the multiple dialogs established
+ from a single request.
+
+ When a tag is generated by a UA for insertion into a request or
+ response, it MUST be globally unique and cryptographically random
+ with at least 32 bits of randomness. A property of this selection
+ requirement is that a UA will place a different tag into the From
+ header of an INVITE than it would place into the To header of the
+ response to the same INVITE. This is needed in order for a UA to
+ invite itself to a session, a common case for "hairpinning" of calls
+ in PSTN gateways. Similarly, two INVITEs for different calls will
+ have different From tags, and two responses for different calls will
+ have different To tags.
+
+ Besides the requirement for global uniqueness, the algorithm for
+ generating a tag is implementation-specific. Tags are helpful in
+ fault tolerant systems, where a dialog is to be recovered on an
+ alternate server after a failure. A UAS can select the tag in such a
+ way that a backup can recognize a request as part of a dialog on the
+ failed server, and therefore determine that it should attempt to
+ recover the dialog and any other state associated with it.
+
+20 Header Fields
+
+ The general syntax for header fields is covered in Section 7.3. This
+ section lists the full set of header fields along with notes on
+ syntax, meaning, and usage. Throughout this section, we use [HX.Y]
+ to refer to Section X.Y of the current HTTP/1.1 specification RFC
+ 2616 [8]. Examples of each header field are given.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 159]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Information about header fields in relation to methods and proxy
+ processing is summarized in Tables 2 and 3.
+
+ The "where" column describes the request and response types in which
+ the header field can be used. Values in this column are:
+
+ R: header field may only appear in requests;
+
+ r: header field may only appear in responses;
+
+ 2xx, 4xx, etc.: A numerical value or range indicates response
+ codes with which the header field can be used;
+
+ c: header field is copied from the request to the response.
+
+ An empty entry in the "where" column indicates that the header
+ field may be present in all requests and responses.
+
+ The "proxy" column describes the operations a proxy may perform on a
+ header field:
+
+ a: A proxy can add or concatenate the header field if not present.
+
+ m: A proxy can modify an existing header field value.
+
+ d: A proxy can delete a header field value.
+
+ r: A proxy must be able to read the header field, and thus this
+ header field cannot be encrypted.
+
+ The next six columns relate to the presence of a header field in a
+ method:
+
+ c: Conditional; requirements on the header field depend on the
+ context of the message.
+
+ m: The header field is mandatory.
+
+ m*: The header field SHOULD be sent, but clients/servers need to
+ be prepared to receive messages without that header field.
+
+ o: The header field is optional.
+
+ t: The header field SHOULD be sent, but clients/servers need to be
+ prepared to receive messages without that header field.
+
+ If a stream-based protocol (such as TCP) is used as a
+ transport, then the header field MUST be sent.
+
+
+
+Rosenberg, et. al. Standards Track [Page 160]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ *: The header field is required if the message body is not empty.
+ See Sections 20.14, 20.15 and 7.4 for details.
+
+ -: The header field is not applicable.
+
+ "Optional" means that an element MAY include the header field in a
+ request or response, and a UA MAY ignore the header field if present
+ in the request or response (The exception to this rule is the Require
+ header field discussed in 20.32). A "mandatory" header field MUST be
+ present in a request, and MUST be understood by the UAS receiving the
+ request. A mandatory response header field MUST be present in the
+ response, and the header field MUST be understood by the UAC
+ processing the response. "Not applicable" means that the header
+ field MUST NOT be present in a request. If one is placed in a
+ request by mistake, it MUST be ignored by the UAS receiving the
+ request. Similarly, a header field labeled "not applicable" for a
+ response means that the UAS MUST NOT place the header field in the
+ response, and the UAC MUST ignore the header field in the response.
+
+ A UA SHOULD ignore extension header parameters that are not
+ understood.
+
+ A compact form of some common header field names is also defined for
+ use when overall message size is an issue.
+
+ The Contact, From, and To header fields contain a URI. If the URI
+ contains a comma, question mark or semicolon, the URI MUST be
+ enclosed in angle brackets (< and >). Any URI parameters are
+ contained within these brackets. If the URI is not enclosed in angle
+ brackets, any semicolon-delimited parameters are header-parameters,
+ not URI parameters.
+
+20.1 Accept
+
+ The Accept header field follows the syntax defined in [H14.1]. The
+ semantics are also identical, with the exception that if no Accept
+ header field is present, the server SHOULD assume a default value of
+ application/sdp.
+
+ An empty Accept header field means that no formats are acceptable.
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 161]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Example:
+
+ Header field where proxy ACK BYE CAN INV OPT REG
+ ___________________________________________________________
+ Accept R - o - o m* o
+ Accept 2xx - - - o m* o
+ Accept 415 - c - c c c
+ Accept-Encoding R - o - o o o
+ Accept-Encoding 2xx - - - o m* o
+ Accept-Encoding 415 - c - c c c
+ Accept-Language R - o - o o o
+ Accept-Language 2xx - - - o m* o
+ Accept-Language 415 - c - c c c
+ Alert-Info R ar - - - o - -
+ Alert-Info 180 ar - - - o - -
+ Allow R - o - o o o
+ Allow 2xx - o - m* m* o
+ Allow r - o - o o o
+ Allow 405 - m - m m m
+ Authentication-Info 2xx - o - o o o
+ Authorization R o o o o o o
+ Call-ID c r m m m m m m
+ Call-Info ar - - - o o o
+ Contact R o - - m o o
+ Contact 1xx - - - o - -
+ Contact 2xx - - - m o o
+ Contact 3xx d - o - o o o
+ Contact 485 - o - o o o
+ Content-Disposition o o - o o o
+ Content-Encoding o o - o o o
+ Content-Language o o - o o o
+ Content-Length ar t t t t t t
+ Content-Type * * - * * *
+ CSeq c r m m m m m m
+ Date a o o o o o o
+ Error-Info 300-699 a - o o o o o
+ Expires - - - o - o
+ From c r m m m m m m
+ In-Reply-To R - - - o - -
+ Max-Forwards R amr m m m m m m
+ Min-Expires 423 - - - - - m
+ MIME-Version o o - o o o
+ Organization ar - - - o o o
+
+ Table 2: Summary of header fields, A--O
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 162]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Header field where proxy ACK BYE CAN INV OPT REG
+ ___________________________________________________________________
+ Priority R ar - - - o - -
+ Proxy-Authenticate 407 ar - m - m m m
+ Proxy-Authenticate 401 ar - o o o o o
+ Proxy-Authorization R dr o o - o o o
+ Proxy-Require R ar - o - o o o
+ Record-Route R ar o o o o o -
+ Record-Route 2xx,18x mr - o o o o -
+ Reply-To - - - o - -
+ Require ar - c - c c c
+ Retry-After 404,413,480,486 - o o o o o
+ 500,503 - o o o o o
+ 600,603 - o o o o o
+ Route R adr c c c c c c
+ Server r - o o o o o
+ Subject R - - - o - -
+ Supported R - o o m* o o
+ Supported 2xx - o o m* m* o
+ Timestamp o o o o o o
+ To c(1) r m m m m m m
+ Unsupported 420 - m - m m m
+ User-Agent o o o o o o
+ Via R amr m m m m m m
+ Via rc dr m m m m m m
+ Warning r - o o o o o
+ WWW-Authenticate 401 ar - m - m m m
+ WWW-Authenticate 407 ar - o - o o o
+
+ Table 3: Summary of header fields, P--Z; (1): copied with possible
+ addition of tag
+
+ Accept: application/sdp;level=1, application/x-private, text/html
+
+20.2 Accept-Encoding
+
+ The Accept-Encoding header field is similar to Accept, but restricts
+ the content-codings [H3.5] that are acceptable in the response. See
+ [H14.3]. The semantics in SIP are identical to those defined in
+ [H14.3].
+
+ An empty Accept-Encoding header field is permissible. It is
+ equivalent to Accept-Encoding: identity, that is, only the identity
+ encoding, meaning no encoding, is permissible.
+
+ If no Accept-Encoding header field is present, the server SHOULD
+ assume a default value of identity.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 163]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ This differs slightly from the HTTP definition, which indicates that
+ when not present, any encoding can be used, but the identity encoding
+ is preferred.
+
+ Example:
+
+ Accept-Encoding: gzip
+
+20.3 Accept-Language
+
+ The Accept-Language header field is used in requests to indicate the
+ preferred languages for reason phrases, session descriptions, or
+ status responses carried as message bodies in the response. If no
+ Accept-Language header field is present, the server SHOULD assume all
+ languages are acceptable to the client.
+
+ The Accept-Language header field follows the syntax defined in
+ [H14.4]. The rules for ordering the languages based on the "q"
+ parameter apply to SIP as well.
+
+ Example:
+
+ Accept-Language: da, en-gb;q=0.8, en;q=0.7
+
+20.4 Alert-Info
+
+ When present in an INVITE request, the Alert-Info header field
+ specifies an alternative ring tone to the UAS. When present in a 180
+ (Ringing) response, the Alert-Info header field specifies an
+ alternative ringback tone to the UAC. A typical usage is for a proxy
+ to insert this header field to provide a distinctive ring feature.
+
+ The Alert-Info header field can introduce security risks. These
+ risks and the ways to handle them are discussed in Section 20.9,
+ which discusses the Call-Info header field since the risks are
+ identical.
+
+ In addition, a user SHOULD be able to disable this feature
+ selectively.
+
+ This helps prevent disruptions that could result from the use of
+ this header field by untrusted elements.
+
+ Example:
+
+ Alert-Info: <http://www.example.com/sounds/moo.wav>
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 164]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+20.5 Allow
+
+ The Allow header field lists the set of methods supported by the UA
+ generating the message.
+
+ All methods, including ACK and CANCEL, understood by the UA MUST be
+ included in the list of methods in the Allow header field, when
+ present. The absence of an Allow header field MUST NOT be
+ interpreted to mean that the UA sending the message supports no
+ methods. Rather, it implies that the UA is not providing any
+ information on what methods it supports.
+
+ Supplying an Allow header field in responses to methods other than
+ OPTIONS reduces the number of messages needed.
+
+ Example:
+
+ Allow: INVITE, ACK, OPTIONS, CANCEL, BYE
+
+20.6 Authentication-Info
+
+ The Authentication-Info header field provides for mutual
+ authentication with HTTP Digest. A UAS MAY include this header field
+ in a 2xx response to a request that was successfully authenticated
+ using digest based on the Authorization header field.
+
+ Syntax and semantics follow those specified in RFC 2617 [17].
+
+ Example:
+
+ Authentication-Info: nextnonce="47364c23432d2e131a5fb210812c"
+
+20.7 Authorization
+
+ The Authorization header field contains authentication credentials of
+ a UA. Section 22.2 overviews the use of the Authorization header
+ field, and Section 22.4 describes the syntax and semantics when used
+ with HTTP authentication.
+
+ This header field, along with Proxy-Authorization, breaks the general
+ rules about multiple header field values. Although not a comma-
+ separated list, this header field name may be present multiple times,
+ and MUST NOT be combined into a single header line using the usual
+ rules described in Section 7.3.
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 165]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ In the example below, there are no quotes around the Digest
+ parameter:
+
+ Authorization: Digest username="Alice", realm="atlanta.com",
+ nonce="84a4cc6f3082121f32b42a2187831a9e",
+ response="7587245234b3434cc3412213e5f113a5432"
+
+20.8 Call-ID
+
+ The Call-ID header field uniquely identifies a particular invitation
+ or all registrations of a particular client. A single multimedia
+ conference can give rise to several calls with different Call-IDs,
+ for example, if a user invites a single individual several times to
+ the same (long-running) conference. Call-IDs are case-sensitive and
+ are simply compared byte-by-byte.
+
+ The compact form of the Call-ID header field is i.
+
+ Examples:
+
+ Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@biloxi.com
+ i:f81d4fae-7dec-11d0-a765-00a0c91e6bf6@192.0.2.4
+
+20.9 Call-Info
+
+ The Call-Info header field provides additional information about the
+ caller or callee, depending on whether it is found in a request or
+ response. The purpose of the URI is described by the "purpose"
+ parameter. The "icon" parameter designates an image suitable as an
+ iconic representation of the caller or callee. The "info" parameter
+ describes the caller or callee in general, for example, through a web
+ page. The "card" parameter provides a business card, for example, in
+ vCard [36] or LDIF [37] formats. Additional tokens can be registered
+ using IANA and the procedures in Section 27.
+
+ Use of the Call-Info header field can pose a security risk. If a
+ callee fetches the URIs provided by a malicious caller, the callee
+ may be at risk for displaying inappropriate or offensive content,
+ dangerous or illegal content, and so on. Therefore, it is
+ RECOMMENDED that a UA only render the information in the Call-Info
+ header field if it can verify the authenticity of the element that
+ originated the header field and trusts that element. This need not
+ be the peer UA; a proxy can insert this header field into requests.
+
+ Example:
+
+ Call-Info: <http://wwww.example.com/alice/photo.jpg> ;purpose=icon,
+ <http://www.example.com/alice/> ;purpose=info
+
+
+
+Rosenberg, et. al. Standards Track [Page 166]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+20.10 Contact
+
+ A Contact header field value provides a URI whose meaning depends on
+ the type of request or response it is in.
+
+ A Contact header field value can contain a display name, a URI with
+ URI parameters, and header parameters.
+
+ This document defines the Contact parameters "q" and "expires".
+ These parameters are only used when the Contact is present in a
+ REGISTER request or response, or in a 3xx response. Additional
+ parameters may be defined in other specifications.
+
+ When the header field value contains a display name, the URI
+ including all URI parameters is enclosed in "<" and ">". If no "<"
+ and ">" are present, all parameters after the URI are header
+ parameters, not URI parameters. The display name can be tokens, or a
+ quoted string, if a larger character set is desired.
+
+ Even if the "display-name" is empty, the "name-addr" form MUST be
+ used if the "addr-spec" contains a comma, semicolon, or question
+ mark. There may or may not be LWS between the display-name and the
+ "<".
+
+ These rules for parsing a display name, URI and URI parameters, and
+ header parameters also apply for the header fields To and From.
+
+ The Contact header field has a role similar to the Location header
+ field in HTTP. However, the HTTP header field only allows one
+ address, unquoted. Since URIs can contain commas and semicolons
+ as reserved characters, they can be mistaken for header or
+ parameter delimiters, respectively.
+
+ The compact form of the Contact header field is m (for "moved").
+
+ Examples:
+
+ Contact: "Mr. Watson" <sip:watson@worcester.bell-telephone.com>
+ ;q=0.7; expires=3600,
+ "Mr. Watson" <mailto:watson@bell-telephone.com> ;q=0.1
+ m: <sips:bob@192.0.2.4>;expires=60
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 167]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+20.11 Content-Disposition
+
+ The Content-Disposition header field describes how the message body
+ or, for multipart messages, a message body part is to be interpreted
+ by the UAC or UAS. This SIP header field extends the MIME Content-
+ Type (RFC 2183 [18]).
+
+ Several new "disposition-types" of the Content-Disposition header are
+ defined by SIP. The value "session" indicates that the body part
+ describes a session, for either calls or early (pre-call) media. The
+ value "render" indicates that the body part should be displayed or
+ otherwise rendered to the user. Note that the value "render" is used
+ rather than "inline" to avoid the connotation that the MIME body is
+ displayed as a part of the rendering of the entire message (since the
+ MIME bodies of SIP messages oftentimes are not displayed to users).
+ For backward-compatibility, if the Content-Disposition header field
+ is missing, the server SHOULD assume bodies of Content-Type
+ application/sdp are the disposition "session", while other content
+ types are "render".
+
+ The disposition type "icon" indicates that the body part contains an
+ image suitable as an iconic representation of the caller or callee
+ that could be rendered informationally by a user agent when a message
+ has been received, or persistently while a dialog takes place. The
+ value "alert" indicates that the body part contains information, such
+ as an audio clip, that should be rendered by the user agent in an
+ attempt to alert the user to the receipt of a request, generally a
+ request that initiates a dialog; this alerting body could for example
+ be rendered as a ring tone for a phone call after a 180 Ringing
+ provisional response has been sent.
+
+ Any MIME body with a "disposition-type" that renders content to the
+ user should only be processed when a message has been properly
+ authenticated.
+
+ The handling parameter, handling-param, describes how the UAS should
+ react if it receives a message body whose content type or disposition
+ type it does not understand. The parameter has defined values of
+ "optional" and "required". If the handling parameter is missing, the
+ value "required" SHOULD be assumed. The handling parameter is
+ described in RFC 3204 [19].
+
+ If this header field is missing, the MIME type determines the default
+ content disposition. If there is none, "render" is assumed.
+
+ Example:
+
+ Content-Disposition: session
+
+
+
+Rosenberg, et. al. Standards Track [Page 168]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+20.12 Content-Encoding
+
+ The Content-Encoding header field is used as a modifier to the
+ "media-type". When present, its value indicates what additional
+ content codings have been applied to the entity-body, and thus what
+ decoding mechanisms MUST be applied in order to obtain the media-type
+ referenced by the Content-Type header field. Content-Encoding is
+ primarily used to allow a body to be compressed without losing the
+ identity of its underlying media type.
+
+ If multiple encodings have been applied to an entity-body, the
+ content codings MUST be listed in the order in which they were
+ applied.
+
+ All content-coding values are case-insensitive. IANA acts as a
+ registry for content-coding value tokens. See [H3.5] for a
+ definition of the syntax for content-coding.
+
+ Clients MAY apply content encodings to the body in requests. A
+ server MAY apply content encodings to the bodies in responses. The
+ server MUST only use encodings listed in the Accept-Encoding header
+ field in the request.
+
+ The compact form of the Content-Encoding header field is e.
+ Examples:
+
+ Content-Encoding: gzip
+ e: tar
+
+20.13 Content-Language
+
+ See [H14.12]. Example:
+
+ Content-Language: fr
+
+20.14 Content-Length
+
+ The Content-Length header field indicates the size of the message-
+ body, in decimal number of octets, sent to the recipient.
+ Applications SHOULD use this field to indicate the size of the
+ message-body to be transferred, regardless of the media type of the
+ entity. If a stream-based protocol (such as TCP) is used as
+ transport, the header field MUST be used.
+
+ The size of the message-body does not include the CRLF separating
+ header fields and body. Any Content-Length greater than or equal to
+ zero is a valid value. If no body is present in a message, then the
+ Content-Length header field value MUST be set to zero.
+
+
+
+Rosenberg, et. al. Standards Track [Page 169]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The ability to omit Content-Length simplifies the creation of
+ cgi-like scripts that dynamically generate responses.
+
+ The compact form of the header field is l.
+
+ Examples:
+
+ Content-Length: 349
+ l: 173
+
+20.15 Content-Type
+
+ The Content-Type header field indicates the media type of the
+ message-body sent to the recipient. The "media-type" element is
+ defined in [H3.7]. The Content-Type header field MUST be present if
+ the body is not empty. If the body is empty, and a Content-Type
+ header field is present, it indicates that the body of the specific
+ type has zero length (for example, an empty audio file).
+
+ The compact form of the header field is c.
+
+ Examples:
+
+ Content-Type: application/sdp
+ c: text/html; charset=ISO-8859-4
+
+20.16 CSeq
+
+ A CSeq header field in a request contains a single decimal sequence
+ number and the request method. The sequence number MUST be
+ expressible as a 32-bit unsigned integer. The method part of CSeq is
+ case-sensitive. The CSeq header field serves to order transactions
+ within a dialog, to provide a means to uniquely identify
+ transactions, and to differentiate between new requests and request
+ retransmissions. Two CSeq header fields are considered equal if the
+ sequence number and the request method are identical. Example:
+
+ CSeq: 4711 INVITE
+
+20.17 Date
+
+ The Date header field contains the date and time. Unlike HTTP/1.1,
+ SIP only supports the most recent RFC 1123 [20] format for dates. As
+ in [H3.3], SIP restricts the time zone in SIP-date to "GMT", while
+ RFC 1123 allows any time zone. An RFC 1123 date is case-sensitive.
+
+ The Date header field reflects the time when the request or response
+ is first sent.
+
+
+
+Rosenberg, et. al. Standards Track [Page 170]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The Date header field can be used by simple end systems without a
+ battery-backed clock to acquire a notion of current time.
+ However, in its GMT form, it requires clients to know their offset
+ from GMT.
+
+ Example:
+
+ Date: Sat, 13 Nov 2010 23:29:00 GMT
+
+20.18 Error-Info
+
+ The Error-Info header field provides a pointer to additional
+ information about the error status response.
+
+ SIP UACs have user interface capabilities ranging from pop-up
+ windows and audio on PC softclients to audio-only on "black"
+ phones or endpoints connected via gateways. Rather than forcing a
+ server generating an error to choose between sending an error
+ status code with a detailed reason phrase and playing an audio
+ recording, the Error-Info header field allows both to be sent.
+ The UAC then has the choice of which error indicator to render to
+ the caller.
+
+ A UAC MAY treat a SIP or SIPS URI in an Error-Info header field as if
+ it were a Contact in a redirect and generate a new INVITE, resulting
+ in a recorded announcement session being established. A non-SIP URI
+ MAY be rendered to the user.
+
+ Examples:
+
+ SIP/2.0 404 The number you have dialed is not in service
+ Error-Info: <sip:not-in-service-recording@atlanta.com>
+
+20.19 Expires
+
+ The Expires header field gives the relative time after which the
+ message (or content) expires.
+
+ The precise meaning of this is method dependent.
+
+ The expiration time in an INVITE does not affect the duration of the
+ actual session that may result from the invitation. Session
+ description protocols may offer the ability to express time limits on
+ the session duration, however.
+
+ The value of this field is an integral number of seconds (in decimal)
+ between 0 and (2**32)-1, measured from the receipt of the request.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 171]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Example:
+
+ Expires: 5
+
+20.20 From
+
+ The From header field indicates the initiator of the request. This
+ may be different from the initiator of the dialog. Requests sent by
+ the callee to the caller use the callee's address in the From header
+ field.
+
+ The optional "display-name" is meant to be rendered by a human user
+ interface. A system SHOULD use the display name "Anonymous" if the
+ identity of the client is to remain hidden. Even if the "display-
+ name" is empty, the "name-addr" form MUST be used if the "addr-spec"
+ contains a comma, question mark, or semicolon. Syntax issues are
+ discussed in Section 7.3.1.
+
+ Two From header fields are equivalent if their URIs match, and their
+ parameters match. Extension parameters in one header field, not
+ present in the other are ignored for the purposes of comparison. This
+ means that the display name and presence or absence of angle brackets
+ do not affect matching.
+
+ See Section 20.10 for the rules for parsing a display name, URI and
+ URI parameters, and header field parameters.
+
+ The compact form of the From header field is f.
+
+ Examples:
+
+ From: "A. G. Bell" <sip:agb@bell-telephone.com> ;tag=a48s
+ From: sip:+12125551212@server.phone2net.com;tag=887s
+ f: Anonymous <sip:c8oqz84zk7z@privacy.org>;tag=hyh8
+
+20.21 In-Reply-To
+
+ The In-Reply-To header field enumerates the Call-IDs that this call
+ references or returns. These Call-IDs may have been cached by the
+ client then included in this header field in a return call.
+
+ This allows automatic call distribution systems to route return
+ calls to the originator of the first call. This also allows
+ callees to filter calls, so that only return calls for calls they
+ originated will be accepted. This field is not a substitute for
+ request authentication.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 172]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Example:
+
+ In-Reply-To: 70710@saturn.bell-tel.com, 17320@saturn.bell-tel.com
+
+20.22 Max-Forwards
+
+ The Max-Forwards header field must be used with any SIP method to
+ limit the number of proxies or gateways that can forward the request
+ to the next downstream server. This can also be useful when the
+ client is attempting to trace a request chain that appears to be
+ failing or looping in mid-chain.
+
+ The Max-Forwards value is an integer in the range 0-255 indicating
+ the remaining number of times this request message is allowed to be
+ forwarded. This count is decremented by each server that forwards
+ the request. The recommended initial value is 70.
+
+ This header field should be inserted by elements that can not
+ otherwise guarantee loop detection. For example, a B2BUA should
+ insert a Max-Forwards header field.
+
+ Example:
+
+ Max-Forwards: 6
+
+20.23 Min-Expires
+
+ The Min-Expires header field conveys the minimum refresh interval
+ supported for soft-state elements managed by that server. This
+ includes Contact header fields that are stored by a registrar. The
+ header field contains a decimal integer number of seconds from 0 to
+ (2**32)-1. The use of the header field in a 423 (Interval Too Brief)
+ response is described in Sections 10.2.8, 10.3, and 21.4.17.
+
+ Example:
+
+ Min-Expires: 60
+
+20.24 MIME-Version
+
+ See [H19.4.1].
+
+ Example:
+
+ MIME-Version: 1.0
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 173]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+20.25 Organization
+
+ The Organization header field conveys the name of the organization to
+ which the SIP element issuing the request or response belongs.
+
+ The field MAY be used by client software to filter calls.
+
+ Example:
+
+ Organization: Boxes by Bob
+
+20.26 Priority
+
+ The Priority header field indicates the urgency of the request as
+ perceived by the client. The Priority header field describes the
+ priority that the SIP request should have to the receiving human or
+ its agent. For example, it may be factored into decisions about call
+ routing and acceptance. For these decisions, a message containing no
+ Priority header field SHOULD be treated as if it specified a Priority
+ of "normal". The Priority header field does not influence the use of
+ communications resources such as packet forwarding priority in
+ routers or access to circuits in PSTN gateways. The header field can
+ have the values "non-urgent", "normal", "urgent", and "emergency",
+ but additional values can be defined elsewhere. It is RECOMMENDED
+ that the value of "emergency" only be used when life, limb, or
+ property are in imminent danger. Otherwise, there are no semantics
+ defined for this header field.
+
+ These are the values of RFC 2076 [38], with the addition of
+ "emergency".
+
+ Examples:
+
+ Subject: A tornado is heading our way!
+ Priority: emergency
+
+ or
+
+ Subject: Weekend plans
+ Priority: non-urgent
+
+20.27 Proxy-Authenticate
+
+ A Proxy-Authenticate header field value contains an authentication
+ challenge.
+
+ The use of this header field is defined in [H14.33]. See Section
+ 22.3 for further details on its usage.
+
+
+
+Rosenberg, et. al. Standards Track [Page 174]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Example:
+
+ Proxy-Authenticate: Digest realm="atlanta.com",
+ domain="sip:ss1.carrier.com", qop="auth",
+ nonce="f84f1cec41e6cbe5aea9c8e88d359",
+ opaque="", stale=FALSE, algorithm=MD5
+
+20.28 Proxy-Authorization
+
+ The Proxy-Authorization header field allows the client to identify
+ itself (or its user) to a proxy that requires authentication. A
+ Proxy-Authorization field value consists of credentials containing
+ the authentication information of the user agent for the proxy and/or
+ realm of the resource being requested.
+
+ See Section 22.3 for a definition of the usage of this header field.
+
+ This header field, along with Authorization, breaks the general rules
+ about multiple header field names. Although not a comma-separated
+ list, this header field name may be present multiple times, and MUST
+ NOT be combined into a single header line using the usual rules
+ described in Section 7.3.1.
+
+ Example:
+
+ Proxy-Authorization: Digest username="Alice", realm="atlanta.com",
+ nonce="c60f3082ee1212b402a21831ae",
+ response="245f23415f11432b3434341c022"
+
+20.29 Proxy-Require
+
+ The Proxy-Require header field is used to indicate proxy-sensitive
+ features that must be supported by the proxy. See Section 20.32 for
+ more details on the mechanics of this message and a usage example.
+
+ Example:
+
+ Proxy-Require: foo
+
+20.30 Record-Route
+
+ The Record-Route header field is inserted by proxies in a request to
+ force future requests in the dialog to be routed through the proxy.
+
+ Examples of its use with the Route header field are described in
+ Sections 16.12.1.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 175]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Example:
+
+ Record-Route: <sip:server10.biloxi.com;lr>,
+ <sip:bigbox3.site3.atlanta.com;lr>
+
+20.31 Reply-To
+
+ The Reply-To header field contains a logical return URI that may be
+ different from the From header field. For example, the URI MAY be
+ used to return missed calls or unestablished sessions. If the user
+ wished to remain anonymous, the header field SHOULD either be omitted
+ from the request or populated in such a way that does not reveal any
+ private information.
+
+ Even if the "display-name" is empty, the "name-addr" form MUST be
+ used if the "addr-spec" contains a comma, question mark, or
+ semicolon. Syntax issues are discussed in Section 7.3.1.
+
+ Example:
+
+ Reply-To: Bob <sip:bob@biloxi.com>
+
+20.32 Require
+
+ The Require header field is used by UACs to tell UASs about options
+ that the UAC expects the UAS to support in order to process the
+ request. Although an optional header field, the Require MUST NOT be
+ ignored if it is present.
+
+ The Require header field contains a list of option tags, described in
+ Section 19.2. Each option tag defines a SIP extension that MUST be
+ understood to process the request. Frequently, this is used to
+ indicate that a specific set of extension header fields need to be
+ understood. A UAC compliant to this specification MUST only include
+ option tags corresponding to standards-track RFCs.
+
+ Example:
+
+ Require: 100rel
+
+20.33 Retry-After
+
+ The Retry-After header field can be used with a 500 (Server Internal
+ Error) or 503 (Service Unavailable) response to indicate how long the
+ service is expected to be unavailable to the requesting client and
+ with a 404 (Not Found), 413 (Request Entity Too Large), 480
+ (Temporarily Unavailable), 486 (Busy Here), 600 (Busy), or 603
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 176]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ (Decline) response to indicate when the called party anticipates
+ being available again. The value of this field is a positive integer
+ number of seconds (in decimal) after the time of the response.
+
+ An optional comment can be used to indicate additional information
+ about the time of callback. An optional "duration" parameter
+ indicates how long the called party will be reachable starting at the
+ initial time of availability. If no duration parameter is given, the
+ service is assumed to be available indefinitely.
+
+ Examples:
+
+ Retry-After: 18000;duration=3600
+ Retry-After: 120 (I'm in a meeting)
+
+20.34 Route
+
+ The Route header field is used to force routing for a request through
+ the listed set of proxies. Examples of the use of the Route header
+ field are in Section 16.12.1.
+
+ Example:
+
+ Route: <sip:bigbox3.site3.atlanta.com;lr>,
+ <sip:server10.biloxi.com;lr>
+
+20.35 Server
+
+ The Server header field contains information about the software used
+ by the UAS to handle the request.
+
+ Revealing the specific software version of the server might allow the
+ server to become more vulnerable to attacks against software that is
+ known to contain security holes. Implementers SHOULD make the Server
+ header field a configurable option.
+
+ Example:
+
+ Server: HomeServer v2
+
+20.36 Subject
+
+ The Subject header field provides a summary or indicates the nature
+ of the call, allowing call filtering without having to parse the
+ session description. The session description does not have to use
+ the same subject indication as the invitation.
+
+ The compact form of the Subject header field is s.
+
+
+
+Rosenberg, et. al. Standards Track [Page 177]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Example:
+
+ Subject: Need more boxes
+ s: Tech Support
+
+20.37 Supported
+
+ The Supported header field enumerates all the extensions supported by
+ the UAC or UAS.
+
+ The Supported header field contains a list of option tags, described
+ in Section 19.2, that are understood by the UAC or UAS. A UA
+ compliant to this specification MUST only include option tags
+ corresponding to standards-track RFCs. If empty, it means that no
+ extensions are supported.
+
+ The compact form of the Supported header field is k.
+
+ Example:
+
+ Supported: 100rel
+
+20.38 Timestamp
+
+ The Timestamp header field describes when the UAC sent the request to
+ the UAS.
+
+ See Section 8.2.6 for details on how to generate a response to a
+ request that contains the header field. Although there is no
+ normative behavior defined here that makes use of the header, it
+ allows for extensions or SIP applications to obtain RTT estimates.
+
+ Example:
+
+ Timestamp: 54
+
+20.39 To
+
+ The To header field specifies the logical recipient of the request.
+
+ The optional "display-name" is meant to be rendered by a human-user
+ interface. The "tag" parameter serves as a general mechanism for
+ dialog identification.
+
+ See Section 19.3 for details of the "tag" parameter.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 178]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Comparison of To header fields for equality is identical to
+ comparison of From header fields. See Section 20.10 for the rules
+ for parsing a display name, URI and URI parameters, and header field
+ parameters.
+
+ The compact form of the To header field is t.
+
+ The following are examples of valid To header fields:
+
+ To: The Operator <sip:operator@cs.columbia.edu>;tag=287447
+ t: sip:+12125551212@server.phone2net.com
+
+20.40 Unsupported
+
+ The Unsupported header field lists the features not supported by the
+ UAS. See Section 20.32 for motivation.
+
+ Example:
+
+ Unsupported: foo
+
+20.41 User-Agent
+
+ The User-Agent header field contains information about the UAC
+ originating the request. The semantics of this header field are
+ defined in [H14.43].
+
+ Revealing the specific software version of the user agent might allow
+ the user agent to become more vulnerable to attacks against software
+ that is known to contain security holes. Implementers SHOULD make
+ the User-Agent header field a configurable option.
+
+ Example:
+
+ User-Agent: Softphone Beta1.5
+
+20.42 Via
+
+ The Via header field indicates the path taken by the request so far
+ and indicates the path that should be followed in routing responses.
+ The branch ID parameter in the Via header field values serves as a
+ transaction identifier, and is used by proxies to detect loops.
+
+ A Via header field value contains the transport protocol used to send
+ the message, the client's host name or network address, and possibly
+ the port number at which it wishes to receive responses. A Via
+ header field value can also contain parameters such as "maddr",
+ "ttl", "received", and "branch", whose meaning and use are described
+
+
+
+Rosenberg, et. al. Standards Track [Page 179]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ in other sections. For implementations compliant to this
+ specification, the value of the branch parameter MUST start with the
+ magic cookie "z9hG4bK", as discussed in Section 8.1.1.7.
+
+ Transport protocols defined here are "UDP", "TCP", "TLS", and "SCTP".
+ "TLS" means TLS over TCP. When a request is sent to a SIPS URI, the
+ protocol still indicates "SIP", and the transport protocol is TLS.
+
+Via: SIP/2.0/UDP erlang.bell-telephone.com:5060;branch=z9hG4bK87asdks7
+Via: SIP/2.0/UDP 192.0.2.1:5060 ;received=192.0.2.207
+ ;branch=z9hG4bK77asjd
+
+ The compact form of the Via header field is v.
+
+ In this example, the message originated from a multi-homed host with
+ two addresses, 192.0.2.1 and 192.0.2.207. The sender guessed wrong
+ as to which network interface would be used. Erlang.bell-
+ telephone.com noticed the mismatch and added a parameter to the
+ previous hop's Via header field value, containing the address that
+ the packet actually came from.
+
+ The host or network address and port number are not required to
+ follow the SIP URI syntax. Specifically, LWS on either side of the
+ ":" or "/" is allowed, as shown here:
+
+ Via: SIP / 2.0 / UDP first.example.com: 4000;ttl=16
+ ;maddr=224.2.0.1 ;branch=z9hG4bKa7c6a8dlze.1
+
+ Even though this specification mandates that the branch parameter be
+ present in all requests, the BNF for the header field indicates that
+ it is optional. This allows interoperation with RFC 2543 elements,
+ which did not have to insert the branch parameter.
+
+ Two Via header fields are equal if their sent-protocol and sent-by
+ fields are equal, both have the same set of parameters, and the
+ values of all parameters are equal.
+
+20.43 Warning
+
+ The Warning header field is used to carry additional information
+ about the status of a response. Warning header field values are sent
+ with responses and contain a three-digit warning code, host name, and
+ warning text.
+
+ The "warn-text" should be in a natural language that is most likely
+ to be intelligible to the human user receiving the response. This
+ decision can be based on any available knowledge, such as the
+ location of the user, the Accept-Language field in a request, or the
+
+
+
+Rosenberg, et. al. Standards Track [Page 180]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Content-Language field in a response. The default language is i-
+ default [21].
+
+ The currently-defined "warn-code"s are listed below, with a
+ recommended warn-text in English and a description of their meaning.
+ These warnings describe failures induced by the session description.
+ The first digit of warning codes beginning with "3" indicates
+ warnings specific to SIP. Warnings 300 through 329 are reserved for
+ indicating problems with keywords in the session description, 330
+ through 339 are warnings related to basic network services requested
+ in the session description, 370 through 379 are warnings related to
+ quantitative QoS parameters requested in the session description, and
+ 390 through 399 are miscellaneous warnings that do not fall into one
+ of the above categories.
+
+ 300 Incompatible network protocol: One or more network protocols
+ contained in the session description are not available.
+
+ 301 Incompatible network address formats: One or more network
+ address formats contained in the session description are not
+ available.
+
+ 302 Incompatible transport protocol: One or more transport
+ protocols described in the session description are not
+ available.
+
+ 303 Incompatible bandwidth units: One or more bandwidth
+ measurement units contained in the session description were
+ not understood.
+
+ 304 Media type not available: One or more media types contained in
+ the session description are not available.
+
+ 305 Incompatible media format: One or more media formats contained
+ in the session description are not available.
+
+ 306 Attribute not understood: One or more of the media attributes
+ in the session description are not supported.
+
+ 307 Session description parameter not understood: A parameter
+ other than those listed above was not understood.
+
+ 330 Multicast not available: The site where the user is located
+ does not support multicast.
+
+ 331 Unicast not available: The site where the user is located does
+ not support unicast communication (usually due to the presence
+ of a firewall).
+
+
+
+Rosenberg, et. al. Standards Track [Page 181]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ 370 Insufficient bandwidth: The bandwidth specified in the session
+ description or defined by the media exceeds that known to be
+ available.
+
+ 399 Miscellaneous warning: The warning text can include arbitrary
+ information to be presented to a human user or logged. A
+ system receiving this warning MUST NOT take any automated
+ action.
+
+ 1xx and 2xx have been taken by HTTP/1.1.
+
+ Additional "warn-code"s can be defined through IANA, as defined in
+ Section 27.2.
+
+ Examples:
+
+ Warning: 307 isi.edu "Session parameter 'foo' not understood"
+ Warning: 301 isi.edu "Incompatible network address type 'E.164'"
+
+20.44 WWW-Authenticate
+
+ A WWW-Authenticate header field value contains an authentication
+ challenge. See Section 22.2 for further details on its usage.
+
+ Example:
+
+ WWW-Authenticate: Digest realm="atlanta.com",
+ domain="sip:boxesbybob.com", qop="auth",
+ nonce="f84f1cec41e6cbe5aea9c8e88d359",
+ opaque="", stale=FALSE, algorithm=MD5
+
+21 Response Codes
+
+ The response codes are consistent with, and extend, HTTP/1.1 response
+ codes. Not all HTTP/1.1 response codes are appropriate, and only
+ those that are appropriate are given here. Other HTTP/1.1 response
+ codes SHOULD NOT be used. Also, SIP defines a new class, 6xx.
+
+21.1 Provisional 1xx
+
+ Provisional responses, also known as informational responses,
+ indicate that the server contacted is performing some further action
+ and does not yet have a definitive response. A server sends a 1xx
+ response if it expects to take more than 200 ms to obtain a final
+ response. Note that 1xx responses are not transmitted reliably.
+ They never cause the client to send an ACK. Provisional (1xx)
+ responses MAY contain message bodies, including session descriptions.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 182]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.1.1 100 Trying
+
+ This response indicates that the request has been received by the
+ next-hop server and that some unspecified action is being taken on
+ behalf of this call (for example, a database is being consulted).
+ This response, like all other provisional responses, stops
+ retransmissions of an INVITE by a UAC. The 100 (Trying) response is
+ different from other provisional responses, in that it is never
+ forwarded upstream by a stateful proxy.
+
+21.1.2 180 Ringing
+
+ The UA receiving the INVITE is trying to alert the user. This
+ response MAY be used to initiate local ringback.
+
+21.1.3 181 Call Is Being Forwarded
+
+ A server MAY use this status code to indicate that the call is being
+ forwarded to a different set of destinations.
+
+21.1.4 182 Queued
+
+ The called party is temporarily unavailable, but the server has
+ decided to queue the call rather than reject it. When the callee
+ becomes available, it will return the appropriate final status
+ response. The reason phrase MAY give further details about the
+ status of the call, for example, "5 calls queued; expected waiting
+ time is 15 minutes". The server MAY issue several 182 (Queued)
+ responses to update the caller about the status of the queued call.
+
+21.1.5 183 Session Progress
+
+ The 183 (Session Progress) response is used to convey information
+ about the progress of the call that is not otherwise classified. The
+ Reason-Phrase, header fields, or message body MAY be used to convey
+ more details about the call progress.
+
+21.2 Successful 2xx
+
+ The request was successful.
+
+21.2.1 200 OK
+
+ The request has succeeded. The information returned with the
+ response depends on the method used in the request.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 183]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.3 Redirection 3xx
+
+ 3xx responses give information about the user's new location, or
+ about alternative services that might be able to satisfy the call.
+
+21.3.1 300 Multiple Choices
+
+ The address in the request resolved to several choices, each with its
+ own specific location, and the user (or UA) can select a preferred
+ communication end point and redirect its request to that location.
+
+ The response MAY include a message body containing a list of resource
+ characteristics and location(s) from which the user or UA can choose
+ the one most appropriate, if allowed by the Accept request header
+ field. However, no MIME types have been defined for this message
+ body.
+
+ The choices SHOULD also be listed as Contact fields (Section 20.10).
+ Unlike HTTP, the SIP response MAY contain several Contact fields or a
+ list of addresses in a Contact field. UAs MAY use the Contact header
+ field value for automatic redirection or MAY ask the user to confirm
+ a choice. However, this specification does not define any standard
+ for such automatic selection.
+
+ This status response is appropriate if the callee can be reached
+ at several different locations and the server cannot or prefers
+ not to proxy the request.
+
+21.3.2 301 Moved Permanently
+
+ The user can no longer be found at the address in the Request-URI,
+ and the requesting client SHOULD retry at the new address given by
+ the Contact header field (Section 20.10). The requestor SHOULD
+ update any local directories, address books, and user location caches
+ with this new value and redirect future requests to the address(es)
+ listed.
+
+21.3.3 302 Moved Temporarily
+
+ The requesting client SHOULD retry the request at the new address(es)
+ given by the Contact header field (Section 20.10). The Request-URI
+ of the new request uses the value of the Contact header field in the
+ response.
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 184]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The duration of the validity of the Contact URI can be indicated
+ through an Expires (Section 20.19) header field or an expires
+ parameter in the Contact header field. Both proxies and UAs MAY
+ cache this URI for the duration of the expiration time. If there is
+ no explicit expiration time, the address is only valid once for
+ recursing, and MUST NOT be cached for future transactions.
+
+ If the URI cached from the Contact header field fails, the Request-
+ URI from the redirected request MAY be tried again a single time.
+
+ The temporary URI may have become out-of-date sooner than the
+ expiration time, and a new temporary URI may be available.
+
+21.3.4 305 Use Proxy
+
+ The requested resource MUST be accessed through the proxy given by
+ the Contact field. The Contact field gives the URI of the proxy.
+ The recipient is expected to repeat this single request via the
+ proxy. 305 (Use Proxy) responses MUST only be generated by UASs.
+
+21.3.5 380 Alternative Service
+
+ The call was not successful, but alternative services are possible.
+
+ The alternative services are described in the message body of the
+ response. Formats for such bodies are not defined here, and may be
+ the subject of future standardization.
+
+21.4 Request Failure 4xx
+
+ 4xx responses are definite failure responses from a particular
+ server. The client SHOULD NOT retry the same request without
+ modification (for example, adding appropriate authorization).
+ However, the same request to a different server might be successful.
+
+21.4.1 400 Bad Request
+
+ The request could not be understood due to malformed syntax. The
+ Reason-Phrase SHOULD identify the syntax problem in more detail, for
+ example, "Missing Call-ID header field".
+
+21.4.2 401 Unauthorized
+
+ The request requires user authentication. This response is issued by
+ UASs and registrars, while 407 (Proxy Authentication Required) is
+ used by proxy servers.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 185]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.4.3 402 Payment Required
+
+ Reserved for future use.
+
+21.4.4 403 Forbidden
+
+ The server understood the request, but is refusing to fulfill it.
+ Authorization will not help, and the request SHOULD NOT be repeated.
+
+21.4.5 404 Not Found
+
+ The server has definitive information that the user does not exist at
+ the domain specified in the Request-URI. This status is also
+ returned if the domain in the Request-URI does not match any of the
+ domains handled by the recipient of the request.
+
+21.4.6 405 Method Not Allowed
+
+ The method specified in the Request-Line is understood, but not
+ allowed for the address identified by the Request-URI.
+
+ The response MUST include an Allow header field containing a list of
+ valid methods for the indicated address.
+
+21.4.7 406 Not Acceptable
+
+ The resource identified by the request is only capable of generating
+ response entities that have content characteristics not acceptable
+ according to the Accept header field sent in the request.
+
+21.4.8 407 Proxy Authentication Required
+
+ This code is similar to 401 (Unauthorized), but indicates that the
+ client MUST first authenticate itself with the proxy. SIP access
+ authentication is explained in Sections 26 and 22.3.
+
+ This status code can be used for applications where access to the
+ communication channel (for example, a telephony gateway) rather than
+ the callee requires authentication.
+
+21.4.9 408 Request Timeout
+
+ The server could not produce a response within a suitable amount of
+ time, for example, if it could not determine the location of the user
+ in time. The client MAY repeat the request without modifications at
+ any later time.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 186]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.4.10 410 Gone
+
+ The requested resource is no longer available at the server and no
+ forwarding address is known. This condition is expected to be
+ considered permanent. If the server does not know, or has no
+ facility to determine, whether or not the condition is permanent, the
+ status code 404 (Not Found) SHOULD be used instead.
+
+21.4.11 413 Request Entity Too Large
+
+ The server is refusing to process a request because the request
+ entity-body is larger than the server is willing or able to process.
+ The server MAY close the connection to prevent the client from
+ continuing the request.
+
+ If the condition is temporary, the server SHOULD include a Retry-
+ After header field to indicate that it is temporary and after what
+ time the client MAY try again.
+
+21.4.12 414 Request-URI Too Long
+
+ The server is refusing to service the request because the Request-URI
+ is longer than the server is willing to interpret.
+
+21.4.13 415 Unsupported Media Type
+
+ The server is refusing to service the request because the message
+ body of the request is in a format not supported by the server for
+ the requested method. The server MUST return a list of acceptable
+ formats using the Accept, Accept-Encoding, or Accept-Language header
+ field, depending on the specific problem with the content. UAC
+ processing of this response is described in Section 8.1.3.5.
+
+21.4.14 416 Unsupported URI Scheme
+
+ The server cannot process the request because the scheme of the URI
+ in the Request-URI is unknown to the server. Client processing of
+ this response is described in Section 8.1.3.5.
+
+21.4.15 420 Bad Extension
+
+ The server did not understand the protocol extension specified in a
+ Proxy-Require (Section 20.29) or Require (Section 20.32) header
+ field. The server MUST include a list of the unsupported extensions
+ in an Unsupported header field in the response. UAC processing of
+ this response is described in Section 8.1.3.5.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 187]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.4.16 421 Extension Required
+
+ The UAS needs a particular extension to process the request, but this
+ extension is not listed in a Supported header field in the request.
+ Responses with this status code MUST contain a Require header field
+ listing the required extensions.
+
+ A UAS SHOULD NOT use this response unless it truly cannot provide any
+ useful service to the client. Instead, if a desirable extension is
+ not listed in the Supported header field, servers SHOULD process the
+ request using baseline SIP capabilities and any extensions supported
+ by the client.
+
+21.4.17 423 Interval Too Brief
+
+ The server is rejecting the request because the expiration time of
+ the resource refreshed by the request is too short. This response
+ can be used by a registrar to reject a registration whose Contact
+ header field expiration time was too small. The use of this response
+ and the related Min-Expires header field are described in Sections
+ 10.2.8, 10.3, and 20.23.
+
+21.4.18 480 Temporarily Unavailable
+
+ The callee's end system was contacted successfully but the callee is
+ currently unavailable (for example, is not logged in, logged in but
+ in a state that precludes communication with the callee, or has
+ activated the "do not disturb" feature). The response MAY indicate a
+ better time to call in the Retry-After header field. The user could
+ also be available elsewhere (unbeknownst to this server). The reason
+ phrase SHOULD indicate a more precise cause as to why the callee is
+ unavailable. This value SHOULD be settable by the UA. Status 486
+ (Busy Here) MAY be used to more precisely indicate a particular
+ reason for the call failure.
+
+ This status is also returned by a redirect or proxy server that
+ recognizes the user identified by the Request-URI, but does not
+ currently have a valid forwarding location for that user.
+
+21.4.19 481 Call/Transaction Does Not Exist
+
+ This status indicates that the UAS received a request that does not
+ match any existing dialog or transaction.
+
+21.4.20 482 Loop Detected
+
+ The server has detected a loop (Section 16.3 Item 4).
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 188]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.4.21 483 Too Many Hops
+
+ The server received a request that contains a Max-Forwards (Section
+ 20.22) header field with the value zero.
+
+21.4.22 484 Address Incomplete
+
+ The server received a request with a Request-URI that was incomplete.
+ Additional information SHOULD be provided in the reason phrase.
+
+ This status code allows overlapped dialing. With overlapped
+ dialing, the client does not know the length of the dialing
+ string. It sends strings of increasing lengths, prompting the
+ user for more input, until it no longer receives a 484 (Address
+ Incomplete) status response.
+
+21.4.23 485 Ambiguous
+
+ The Request-URI was ambiguous. The response MAY contain a listing of
+ possible unambiguous addresses in Contact header fields. Revealing
+ alternatives can infringe on privacy of the user or the organization.
+ It MUST be possible to configure a server to respond with status 404
+ (Not Found) or to suppress the listing of possible choices for
+ ambiguous Request-URIs.
+
+ Example response to a request with the Request-URI
+ sip:lee@example.com:
+
+ SIP/2.0 485 Ambiguous
+ Contact: Carol Lee <sip:carol.lee@example.com>
+ Contact: Ping Lee <sip:p.lee@example.com>
+ Contact: Lee M. Foote <sips:lee.foote@example.com>
+
+ Some email and voice mail systems provide this functionality. A
+ status code separate from 3xx is used since the semantics are
+ different: for 300, it is assumed that the same person or service
+ will be reached by the choices provided. While an automated
+ choice or sequential search makes sense for a 3xx response, user
+ intervention is required for a 485 (Ambiguous) response.
+
+21.4.24 486 Busy Here
+
+ The callee's end system was contacted successfully, but the callee is
+ currently not willing or able to take additional calls at this end
+ system. The response MAY indicate a better time to call in the
+ Retry-After header field. The user could also be available
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 189]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ elsewhere, such as through a voice mail service. Status 600 (Busy
+ Everywhere) SHOULD be used if the client knows that no other end
+ system will be able to accept this call.
+
+21.4.25 487 Request Terminated
+
+ The request was terminated by a BYE or CANCEL request. This response
+ is never returned for a CANCEL request itself.
+
+21.4.26 488 Not Acceptable Here
+
+ The response has the same meaning as 606 (Not Acceptable), but only
+ applies to the specific resource addressed by the Request-URI and the
+ request may succeed elsewhere.
+
+ A message body containing a description of media capabilities MAY be
+ present in the response, which is formatted according to the Accept
+ header field in the INVITE (or application/sdp if not present), the
+ same as a message body in a 200 (OK) response to an OPTIONS request.
+
+21.4.27 491 Request Pending
+
+ The request was received by a UAS that had a pending request within
+ the same dialog. Section 14.2 describes how such "glare" situations
+ are resolved.
+
+21.4.28 493 Undecipherable
+
+ The request was received by a UAS that contained an encrypted MIME
+ body for which the recipient does not possess or will not provide an
+ appropriate decryption key. This response MAY have a single body
+ containing an appropriate public key that should be used to encrypt
+ MIME bodies sent to this UA. Details of the usage of this response
+ code can be found in Section 23.2.
+
+21.5 Server Failure 5xx
+
+ 5xx responses are failure responses given when a server itself has
+ erred.
+
+21.5.1 500 Server Internal Error
+
+ The server encountered an unexpected condition that prevented it from
+ fulfilling the request. The client MAY display the specific error
+ condition and MAY retry the request after several seconds.
+
+ If the condition is temporary, the server MAY indicate when the
+ client may retry the request using the Retry-After header field.
+
+
+
+Rosenberg, et. al. Standards Track [Page 190]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.5.2 501 Not Implemented
+
+ The server does not support the functionality required to fulfill the
+ request. This is the appropriate response when a UAS does not
+ recognize the request method and is not capable of supporting it for
+ any user. (Proxies forward all requests regardless of method.)
+
+ Note that a 405 (Method Not Allowed) is sent when the server
+ recognizes the request method, but that method is not allowed or
+ supported.
+
+21.5.3 502 Bad Gateway
+
+ The server, while acting as a gateway or proxy, received an invalid
+ response from the downstream server it accessed in attempting to
+ fulfill the request.
+
+21.5.4 503 Service Unavailable
+
+ The server is temporarily unable to process the request due to a
+ temporary overloading or maintenance of the server. The server MAY
+ indicate when the client should retry the request in a Retry-After
+ header field. If no Retry-After is given, the client MUST act as if
+ it had received a 500 (Server Internal Error) response.
+
+ A client (proxy or UAC) receiving a 503 (Service Unavailable) SHOULD
+ attempt to forward the request to an alternate server. It SHOULD NOT
+ forward any other requests to that server for the duration specified
+ in the Retry-After header field, if present.
+
+ Servers MAY refuse the connection or drop the request instead of
+ responding with 503 (Service Unavailable).
+
+21.5.5 504 Server Time-out
+
+ The server did not receive a timely response from an external server
+ it accessed in attempting to process the request. 408 (Request
+ Timeout) should be used instead if there was no response within the
+ period specified in the Expires header field from the upstream
+ server.
+
+21.5.6 505 Version Not Supported
+
+ The server does not support, or refuses to support, the SIP protocol
+ version that was used in the request. The server is indicating that
+ it is unable or unwilling to complete the request using the same
+ major version as the client, other than with this error message.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 191]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+21.5.7 513 Message Too Large
+
+ The server was unable to process the request since the message length
+ exceeded its capabilities.
+
+21.6 Global Failures 6xx
+
+ 6xx responses indicate that a server has definitive information about
+ a particular user, not just the particular instance indicated in the
+ Request-URI.
+
+21.6.1 600 Busy Everywhere
+
+ The callee's end system was contacted successfully but the callee is
+ busy and does not wish to take the call at this time. The response
+ MAY indicate a better time to call in the Retry-After header field.
+ If the callee does not wish to reveal the reason for declining the
+ call, the callee uses status code 603 (Decline) instead. This status
+ response is returned only if the client knows that no other end point
+ (such as a voice mail system) will answer the request. Otherwise,
+ 486 (Busy Here) should be returned.
+
+21.6.2 603 Decline
+
+ The callee's machine was successfully contacted but the user
+ explicitly does not wish to or cannot participate. The response MAY
+ indicate a better time to call in the Retry-After header field. This
+ status response is returned only if the client knows that no other
+ end point will answer the request.
+
+21.6.3 604 Does Not Exist Anywhere
+
+ The server has authoritative information that the user indicated in
+ the Request-URI does not exist anywhere.
+
+21.6.4 606 Not Acceptable
+
+ The user's agent was contacted successfully but some aspects of the
+ session description such as the requested media, bandwidth, or
+ addressing style were not acceptable.
+
+ A 606 (Not Acceptable) response means that the user wishes to
+ communicate, but cannot adequately support the session described.
+ The 606 (Not Acceptable) response MAY contain a list of reasons in a
+ Warning header field describing why the session described cannot be
+ supported. Warning reason codes are listed in Section 20.43.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 192]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ A message body containing a description of media capabilities MAY be
+ present in the response, which is formatted according to the Accept
+ header field in the INVITE (or application/sdp if not present), the
+ same as a message body in a 200 (OK) response to an OPTIONS request.
+
+ It is hoped that negotiation will not frequently be needed, and when
+ a new user is being invited to join an already existing conference,
+ negotiation may not be possible. It is up to the invitation
+ initiator to decide whether or not to act on a 606 (Not Acceptable)
+ response.
+
+ This status response is returned only if the client knows that no
+ other end point will answer the request.
+
+22 Usage of HTTP Authentication
+
+ SIP provides a stateless, challenge-based mechanism for
+ authentication that is based on authentication in HTTP. Any time
+ that a proxy server or UA receives a request (with the exceptions
+ given in Section 22.1), it MAY challenge the initiator of the request
+ to provide assurance of its identity. Once the originator has been
+ identified, the recipient of the request SHOULD ascertain whether or
+ not this user is authorized to make the request in question. No
+ authorization systems are recommended or discussed in this document.
+
+ The "Digest" authentication mechanism described in this section
+ provides message authentication and replay protection only, without
+ message integrity or confidentiality. Protective measures above and
+ beyond those provided by Digest need to be taken to prevent active
+ attackers from modifying SIP requests and responses.
+
+ Note that due to its weak security, the usage of "Basic"
+ authentication has been deprecated. Servers MUST NOT accept
+ credentials using the "Basic" authorization scheme, and servers also
+ MUST NOT challenge with "Basic". This is a change from RFC 2543.
+
+22.1 Framework
+
+ The framework for SIP authentication closely parallels that of HTTP
+ (RFC 2617 [17]). In particular, the BNF for auth-scheme, auth-param,
+ challenge, realm, realm-value, and credentials is identical (although
+ the usage of "Basic" as a scheme is not permitted). In SIP, a UAS
+ uses the 401 (Unauthorized) response to challenge the identity of a
+ UAC. Additionally, registrars and redirect servers MAY make use of
+ 401 (Unauthorized) responses for authentication, but proxies MUST
+ NOT, and instead MAY use the 407 (Proxy Authentication Required)
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 193]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ response. The requirements for inclusion of the Proxy-Authenticate,
+ Proxy-Authorization, WWW-Authenticate, and Authorization in the
+ various messages are identical to those described in RFC 2617 [17].
+
+ Since SIP does not have the concept of a canonical root URL, the
+ notion of protection spaces is interpreted differently in SIP. The
+ realm string alone defines the protection domain. This is a change
+ from RFC 2543, in which the Request-URI and the realm together
+ defined the protection domain.
+
+ This previous definition of protection domain caused some amount
+ of confusion since the Request-URI sent by the UAC and the
+ Request-URI received by the challenging server might be different,
+ and indeed the final form of the Request-URI might not be known to
+ the UAC. Also, the previous definition depended on the presence
+ of a SIP URI in the Request-URI and seemed to rule out alternative
+ URI schemes (for example, the tel URL).
+
+ Operators of user agents or proxy servers that will authenticate
+ received requests MUST adhere to the following guidelines for
+ creation of a realm string for their server:
+
+ o Realm strings MUST be globally unique. It is RECOMMENDED that
+ a realm string contain a hostname or domain name, following the
+ recommendation in Section 3.2.1 of RFC 2617 [17].
+
+ o Realm strings SHOULD present a human-readable identifier that
+ can be rendered to a user.
+
+ For example:
+
+ INVITE sip:bob@biloxi.com SIP/2.0
+ Authorization: Digest realm="biloxi.com", <...>
+
+ Generally, SIP authentication is meaningful for a specific realm, a
+ protection domain. Thus, for Digest authentication, each such
+ protection domain has its own set of usernames and passwords. If a
+ server does not require authentication for a particular request, it
+ MAY accept a default username, "anonymous", which has no password
+ (password of ""). Similarly, UACs representing many users, such as
+ PSTN gateways, MAY have their own device-specific username and
+ password, rather than accounts for particular users, for their realm.
+
+ While a server can legitimately challenge most SIP requests, there
+ are two requests defined by this document that require special
+ handling for authentication: ACK and CANCEL.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 194]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Under an authentication scheme that uses responses to carry values
+ used to compute nonces (such as Digest), some problems come up for
+ any requests that take no response, including ACK. For this reason,
+ any credentials in the INVITE that were accepted by a server MUST be
+ accepted by that server for the ACK. UACs creating an ACK message
+ will duplicate all of the Authorization and Proxy-Authorization
+ header field values that appeared in the INVITE to which the ACK
+ corresponds. Servers MUST NOT attempt to challenge an ACK.
+
+ Although the CANCEL method does take a response (a 2xx), servers MUST
+ NOT attempt to challenge CANCEL requests since these requests cannot
+ be resubmitted. Generally, a CANCEL request SHOULD be accepted by a
+ server if it comes from the same hop that sent the request being
+ canceled (provided that some sort of transport or network layer
+ security association, as described in Section 26.2.1, is in place).
+
+ When a UAC receives a challenge, it SHOULD render to the user the
+ contents of the "realm" parameter in the challenge (which appears in
+ either a WWW-Authenticate header field or Proxy-Authenticate header
+ field) if the UAC device does not already know of a credential for
+ the realm in question. A service provider that pre-configures UAs
+ with credentials for its realm should be aware that users will not
+ have the opportunity to present their own credentials for this realm
+ when challenged at a pre-configured device.
+
+ Finally, note that even if a UAC can locate credentials that are
+ associated with the proper realm, the potential exists that these
+ credentials may no longer be valid or that the challenging server
+ will not accept these credentials for whatever reason (especially
+ when "anonymous" with no password is submitted). In this instance a
+ server may repeat its challenge, or it may respond with a 403
+ Forbidden. A UAC MUST NOT re-attempt requests with the credentials
+ that have just been rejected (though the request may be retried if
+ the nonce was stale).
+
+22.2 User-to-User Authentication
+
+ When a UAS receives a request from a UAC, the UAS MAY authenticate
+ the originator before the request is processed. If no credentials
+ (in the Authorization header field) are provided in the request, the
+ UAS can challenge the originator to provide credentials by rejecting
+ the request with a 401 (Unauthorized) status code.
+
+ The WWW-Authenticate response-header field MUST be included in 401
+ (Unauthorized) response messages. The field value consists of at
+ least one challenge that indicates the authentication scheme(s) and
+ parameters applicable to the realm.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 195]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ An example of the WWW-Authenticate header field in a 401 challenge
+ is:
+
+ WWW-Authenticate: Digest
+ realm="biloxi.com",
+ qop="auth,auth-int",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+ When the originating UAC receives the 401 (Unauthorized), it SHOULD,
+ if it is able, re-originate the request with the proper credentials.
+ The UAC may require input from the originating user before
+ proceeding. Once authentication credentials have been supplied
+ (either directly by the user, or discovered in an internal keyring),
+ UAs SHOULD cache the credentials for a given value of the To header
+ field and "realm" and attempt to re-use these values on the next
+ request for that destination. UAs MAY cache credentials in any way
+ they would like.
+
+ If no credentials for a realm can be located, UACs MAY attempt to
+ retry the request with a username of "anonymous" and no password (a
+ password of "").
+
+ Once credentials have been located, any UA that wishes to
+ authenticate itself with a UAS or registrar -- usually, but not
+ necessarily, after receiving a 401 (Unauthorized) response -- MAY do
+ so by including an Authorization header field with the request. The
+ Authorization field value consists of credentials containing the
+ authentication information of the UA for the realm of the resource
+ being requested as well as parameters required in support of
+ authentication and replay protection.
+
+ An example of the Authorization header field is:
+
+ Authorization: Digest username="bob",
+ realm="biloxi.com",
+ nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
+ uri="sip:bob@biloxi.com",
+ qop=auth,
+ nc=00000001,
+ cnonce="0a4f113b",
+ response="6629fae49393a05397450978507c4ef1",
+ opaque="5ccc069c403ebaf9f0171e9517f40e41"
+
+ When a UAC resubmits a request with its credentials after receiving a
+ 401 (Unauthorized) or 407 (Proxy Authentication Required) response,
+ it MUST increment the CSeq header field value as it would normally
+ when sending an updated request.
+
+
+
+Rosenberg, et. al. Standards Track [Page 196]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+22.3 Proxy-to-User Authentication
+
+ Similarly, when a UAC sends a request to a proxy server, the proxy
+ server MAY authenticate the originator before the request is
+ processed. If no credentials (in the Proxy-Authorization header
+ field) are provided in the request, the proxy can challenge the
+ originator to provide credentials by rejecting the request with a 407
+ (Proxy Authentication Required) status code. The proxy MUST populate
+ the 407 (Proxy Authentication Required) message with a Proxy-
+ Authenticate header field value applicable to the proxy for the
+ requested resource.
+
+ The use of Proxy-Authenticate and Proxy-Authorization parallel that
+ described in [17], with one difference. Proxies MUST NOT add values
+ to the Proxy-Authorization header field. All 407 (Proxy
+ Authentication Required) responses MUST be forwarded upstream toward
+ the UAC following the procedures for any other response. It is the
+ UAC's responsibility to add the Proxy-Authorization header field
+ value containing credentials for the realm of the proxy that has
+ asked for authentication.
+
+ If a proxy were to resubmit a request adding a Proxy-Authorization
+ header field value, it would need to increment the CSeq in the new
+ request. However, this would cause the UAC that submitted the
+ original request to discard a response from the UAS, as the CSeq
+ value would be different.
+
+ When the originating UAC receives the 407 (Proxy Authentication
+ Required) it SHOULD, if it is able, re-originate the request with the
+ proper credentials. It should follow the same procedures for the
+ display of the "realm" parameter that are given above for responding
+ to 401.
+
+ If no credentials for a realm can be located, UACs MAY attempt to
+ retry the request with a username of "anonymous" and no password (a
+ password of "").
+
+ The UAC SHOULD also cache the credentials used in the re-originated
+ request.
+
+ The following rule is RECOMMENDED for proxy credential caching:
+
+ If a UA receives a Proxy-Authenticate header field value in a 401/407
+ response to a request with a particular Call-ID, it should
+ incorporate credentials for that realm in all subsequent requests
+ that contain the same Call-ID. These credentials MUST NOT be cached
+ across dialogs; however, if a UA is configured with the realm of its
+ local outbound proxy, when one exists, then the UA MAY cache
+
+
+
+Rosenberg, et. al. Standards Track [Page 197]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ credentials for that realm across dialogs. Note that this does mean
+ a future request in a dialog could contain credentials that are not
+ needed by any proxy along the Route header path.
+
+ Any UA that wishes to authenticate itself to a proxy server --
+ usually, but not necessarily, after receiving a 407 (Proxy
+ Authentication Required) response -- MAY do so by including a Proxy-
+ Authorization header field value with the request. The Proxy-
+ Authorization request-header field allows the client to identify
+ itself (or its user) to a proxy that requires authentication. The
+ Proxy-Authorization header field value consists of credentials
+ containing the authentication information of the UA for the proxy
+ and/or realm of the resource being requested.
+
+ A Proxy-Authorization header field value applies only to the proxy
+ whose realm is identified in the "realm" parameter (this proxy may
+ previously have demanded authentication using the Proxy-Authenticate
+ field). When multiple proxies are used in a chain, a Proxy-
+ Authorization header field value MUST NOT be consumed by any proxy
+ whose realm does not match the "realm" parameter specified in that
+ value.
+
+ Note that if an authentication scheme that does not support realms is
+ used in the Proxy-Authorization header field, a proxy server MUST
+ attempt to parse all Proxy-Authorization header field values to
+ determine whether one of them has what the proxy server considers to
+ be valid credentials. Because this is potentially very time-
+ consuming in large networks, proxy servers SHOULD use an
+ authentication scheme that supports realms in the Proxy-Authorization
+ header field.
+
+ If a request is forked (as described in Section 16.7), various proxy
+ servers and/or UAs may wish to challenge the UAC. In this case, the
+ forking proxy server is responsible for aggregating these challenges
+ into a single response. Each WWW-Authenticate and Proxy-Authenticate
+ value received in responses to the forked request MUST be placed into
+ the single response that is sent by the forking proxy to the UA; the
+ ordering of these header field values is not significant.
+
+ When a proxy server issues a challenge in response to a request,
+ it will not proxy the request until the UAC has retried the
+ request with valid credentials. A forking proxy may forward a
+ request simultaneously to multiple proxy servers that require
+ authentication, each of which in turn will not forward the request
+ until the originating UAC has authenticated itself in their
+ respective realm. If the UAC does not provide credentials for
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 198]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ each challenge, the proxy servers that issued the challenges will
+ not forward requests to the UA where the destination user might be
+ located, and therefore, the virtues of forking are largely lost.
+
+ When resubmitting its request in response to a 401 (Unauthorized) or
+ 407 (Proxy Authentication Required) that contains multiple
+ challenges, a UAC MAY include an Authorization value for each WWW-
+ Authenticate value and a Proxy-Authorization value for each Proxy-
+ Authenticate value for which the UAC wishes to supply a credential.
+ As noted above, multiple credentials in a request SHOULD be
+ differentiated by the "realm" parameter.
+
+ It is possible for multiple challenges associated with the same realm
+ to appear in the same 401 (Unauthorized) or 407 (Proxy Authentication
+ Required). This can occur, for example, when multiple proxies within
+ the same administrative domain, which use a common realm, are reached
+ by a forking request. When it retries a request, a UAC MAY therefore
+ supply multiple credentials in Authorization or Proxy-Authorization
+ header fields with the same "realm" parameter value. The same
+ credentials SHOULD be used for the same realm.
+
+22.4 The Digest Authentication Scheme
+
+ This section describes the modifications and clarifications required
+ to apply the HTTP Digest authentication scheme to SIP. The SIP
+ scheme usage is almost completely identical to that for HTTP [17].
+
+ Since RFC 2543 is based on HTTP Digest as defined in RFC 2069 [39],
+ SIP servers supporting RFC 2617 MUST ensure they are backwards
+ compatible with RFC 2069. Procedures for this backwards
+ compatibility are specified in RFC 2617. Note, however, that SIP
+ servers MUST NOT accept or request Basic authentication.
+
+ The rules for Digest authentication follow those defined in [17],
+ with "HTTP/1.1" replaced by "SIP/2.0" in addition to the following
+ differences:
+
+ 1. The URI included in the challenge has the following BNF:
+
+ URI = SIP-URI / SIPS-URI
+
+ 2. The BNF in RFC 2617 has an error in that the 'uri' parameter
+ of the Authorization header field for HTTP Digest
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 199]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ authentication is not enclosed in quotation marks. (The
+ example in Section 3.5 of RFC 2617 is correct.) For SIP, the
+ 'uri' MUST be enclosed in quotation marks.
+
+ 3. The BNF for digest-uri-value is:
+
+ digest-uri-value = Request-URI ; as defined in Section 25
+
+ 4. The example procedure for choosing a nonce based on Etag does
+ not work for SIP.
+
+ 5. The text in RFC 2617 [17] regarding cache operation does not
+ apply to SIP.
+
+ 6. RFC 2617 [17] requires that a server check that the URI in the
+ request line and the URI included in the Authorization header
+ field point to the same resource. In a SIP context, these two
+ URIs may refer to different users, due to forwarding at some
+ proxy. Therefore, in SIP, a server MAY check that the
+ Request-URI in the Authorization header field value
+ corresponds to a user for whom the server is willing to accept
+ forwarded or direct requests, but it is not necessarily a
+ failure if the two fields are not equivalent.
+
+ 7. As a clarification to the calculation of the A2 value for
+ message integrity assurance in the Digest authentication
+ scheme, implementers should assume, when the entity-body is
+ empty (that is, when SIP messages have no body) that the hash
+ of the entity-body resolves to the MD5 hash of an empty
+ string, or:
+
+ H(entity-body) = MD5("") =
+ "d41d8cd98f00b204e9800998ecf8427e"
+
+ 8. RFC 2617 notes that a cnonce value MUST NOT be sent in an
+ Authorization (and by extension Proxy-Authorization) header
+ field if no qop directive has been sent. Therefore, any
+ algorithms that have a dependency on the cnonce (including
+ "MD5-Sess") require that the qop directive be sent. Use of
+ the "qop" parameter is optional in RFC 2617 for the purposes
+ of backwards compatibility with RFC 2069; since RFC 2543 was
+ based on RFC 2069, the "qop" parameter must unfortunately
+ remain optional for clients and servers to receive. However,
+ servers MUST always send a "qop" parameter in WWW-Authenticate
+ and Proxy-Authenticate header field values. If a client
+ receives a "qop" parameter in a challenge header field, it
+ MUST send the "qop" parameter in any resulting authorization
+ header field.
+
+
+
+Rosenberg, et. al. Standards Track [Page 200]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ RFC 2543 did not allow usage of the Authentication-Info header field
+ (it effectively used RFC 2069). However, we now allow usage of this
+ header field, since it provides integrity checks over the bodies and
+ provides mutual authentication. RFC 2617 [17] defines mechanisms for
+ backwards compatibility using the qop attribute in the request.
+ These mechanisms MUST be used by a server to determine if the client
+ supports the new mechanisms in RFC 2617 that were not specified in
+ RFC 2069.
+
+23 S/MIME
+
+ SIP messages carry MIME bodies and the MIME standard includes
+ mechanisms for securing MIME contents to ensure both integrity and
+ confidentiality (including the 'multipart/signed' and
+ 'application/pkcs7-mime' MIME types, see RFC 1847 [22], RFC 2630 [23]
+ and RFC 2633 [24]). Implementers should note, however, that there
+ may be rare network intermediaries (not typical proxy servers) that
+ rely on viewing or modifying the bodies of SIP messages (especially
+ SDP), and that secure MIME may prevent these sorts of intermediaries
+ from functioning.
+
+ This applies particularly to certain types of firewalls.
+
+ The PGP mechanism for encrypting the header fields and bodies of
+ SIP messages described in RFC 2543 has been deprecated.
+
+23.1 S/MIME Certificates
+
+ The certificates that are used to identify an end-user for the
+ purposes of S/MIME differ from those used by servers in one important
+ respect - rather than asserting that the identity of the holder
+ corresponds to a particular hostname, these certificates assert that
+ the holder is identified by an end-user address. This address is
+ composed of the concatenation of the "userinfo" "@" and "domainname"
+ portions of a SIP or SIPS URI (in other words, an email address of
+ the form "bob@biloxi.com"), most commonly corresponding to a user's
+ address-of-record.
+
+ These certificates are also associated with keys that are used to
+ sign or encrypt bodies of SIP messages. Bodies are signed with the
+ private key of the sender (who may include their public key with the
+ message as appropriate), but bodies are encrypted with the public key
+ of the intended recipient. Obviously, senders must have
+ foreknowledge of the public key of recipients in order to encrypt
+ message bodies. Public keys can be stored within a UA on a virtual
+ keyring.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 201]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Each user agent that supports S/MIME MUST contain a keyring
+ specifically for end-users' certificates. This keyring should map
+ between addresses of record and corresponding certificates. Over
+ time, users SHOULD use the same certificate when they populate the
+ originating URI of signaling (the From header field) with the same
+ address-of-record.
+
+ Any mechanisms depending on the existence of end-user certificates
+ are seriously limited in that there is virtually no consolidated
+ authority today that provides certificates for end-user applications.
+ However, users SHOULD acquire certificates from known public
+ certificate authorities. As an alternative, users MAY create self-
+ signed certificates. The implications of self-signed certificates
+ are explored further in Section 26.4.2. Implementations may also use
+ pre-configured certificates in deployments in which a previous trust
+ relationship exists between all SIP entities.
+
+ Above and beyond the problem of acquiring an end-user certificate,
+ there are few well-known centralized directories that distribute
+ end-user certificates. However, the holder of a certificate SHOULD
+ publish their certificate in any public directories as appropriate.
+ Similarly, UACs SHOULD support a mechanism for importing (manually or
+ automatically) certificates discovered in public directories
+ corresponding to the target URIs of SIP requests.
+
+23.2 S/MIME Key Exchange
+
+ SIP itself can also be used as a means to distribute public keys in
+ the following manner.
+
+ Whenever the CMS SignedData message is used in S/MIME for SIP, it
+ MUST contain the certificate bearing the public key necessary to
+ verify the signature.
+
+ When a UAC sends a request containing an S/MIME body that initiates a
+ dialog, or sends a non-INVITE request outside the context of a
+ dialog, the UAC SHOULD structure the body as an S/MIME
+ 'multipart/signed' CMS SignedData body. If the desired CMS service
+ is EnvelopedData (and the public key of the target user is known),
+ the UAC SHOULD send the EnvelopedData message encapsulated within a
+ SignedData message.
+
+ When a UAS receives a request containing an S/MIME CMS body that
+ includes a certificate, the UAS SHOULD first validate the
+ certificate, if possible, with any available root certificates for
+ certificate authorities. The UAS SHOULD also determine the subject
+ of the certificate (for S/MIME, the SubjectAltName will contain the
+ appropriate identity) and compare this value to the From header field
+
+
+
+Rosenberg, et. al. Standards Track [Page 202]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ of the request. If the certificate cannot be verified, because it is
+ self-signed, or signed by no known authority, or if it is verifiable
+ but its subject does not correspond to the From header field of
+ request, the UAS MUST notify its user of the status of the
+ certificate (including the subject of the certificate, its signer,
+ and any key fingerprint information) and request explicit permission
+ before proceeding. If the certificate was successfully verified and
+ the subject of the certificate corresponds to the From header field
+ of the SIP request, or if the user (after notification) explicitly
+ authorizes the use of the certificate, the UAS SHOULD add this
+ certificate to a local keyring, indexed by the address-of-record of
+ the holder of the certificate.
+
+ When a UAS sends a response containing an S/MIME body that answers
+ the first request in a dialog, or a response to a non-INVITE request
+ outside the context of a dialog, the UAS SHOULD structure the body as
+ an S/MIME 'multipart/signed' CMS SignedData body. If the desired CMS
+ service is EnvelopedData, the UAS SHOULD send the EnvelopedData
+ message encapsulated within a SignedData message.
+
+ When a UAC receives a response containing an S/MIME CMS body that
+ includes a certificate, the UAC SHOULD first validate the
+ certificate, if possible, with any appropriate root certificate. The
+ UAC SHOULD also determine the subject of the certificate and compare
+ this value to the To field of the response; although the two may very
+ well be different, and this is not necessarily indicative of a
+ security breach. If the certificate cannot be verified because it is
+ self-signed, or signed by no known authority, the UAC MUST notify its
+ user of the status of the certificate (including the subject of the
+ certificate, its signator, and any key fingerprint information) and
+ request explicit permission before proceeding. If the certificate
+ was successfully verified, and the subject of the certificate
+ corresponds to the To header field in the response, or if the user
+ (after notification) explicitly authorizes the use of the
+ certificate, the UAC SHOULD add this certificate to a local keyring,
+ indexed by the address-of-record of the holder of the certificate.
+ If the UAC had not transmitted its own certificate to the UAS in any
+ previous transaction, it SHOULD use a CMS SignedData body for its
+ next request or response.
+
+ On future occasions, when the UA receives requests or responses that
+ contain a From header field corresponding to a value in its keyring,
+ the UA SHOULD compare the certificate offered in these messages with
+ the existing certificate in its keyring. If there is a discrepancy,
+ the UA MUST notify its user of a change of the certificate
+ (preferably in terms that indicate that this is a potential security
+ breach) and acquire the user's permission before continuing to
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 203]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ process the signaling. If the user authorizes this certificate, it
+ SHOULD be added to the keyring alongside any previous value(s) for
+ this address-of-record.
+
+ Note well however, that this key exchange mechanism does not
+ guarantee the secure exchange of keys when self-signed certificates,
+ or certificates signed by an obscure authority, are used - it is
+ vulnerable to well-known attacks. In the opinion of the authors,
+ however, the security it provides is proverbially better than
+ nothing; it is in fact comparable to the widely used SSH application.
+ These limitations are explored in greater detail in Section 26.4.2.
+
+ If a UA receives an S/MIME body that has been encrypted with a public
+ key unknown to the recipient, it MUST reject the request with a 493
+ (Undecipherable) response. This response SHOULD contain a valid
+ certificate for the respondent (corresponding, if possible, to any
+ address of record given in the To header field of the rejected
+ request) within a MIME body with a 'certs-only' "smime-type"
+ parameter.
+
+ A 493 (Undecipherable) sent without any certificate indicates that
+ the respondent cannot or will not utilize S/MIME encrypted messages,
+ though they may still support S/MIME signatures.
+
+ Note that a user agent that receives a request containing an S/MIME
+ body that is not optional (with a Content-Disposition header
+ "handling" parameter of "required") MUST reject the request with a
+ 415 Unsupported Media Type response if the MIME type is not
+ understood. A user agent that receives such a response when S/MIME
+ is sent SHOULD notify its user that the remote device does not
+ support S/MIME, and it MAY subsequently resend the request without
+ S/MIME, if appropriate; however, this 415 response may constitute a
+ downgrade attack.
+
+ If a user agent sends an S/MIME body in a request, but receives a
+ response that contains a MIME body that is not secured, the UAC
+ SHOULD notify its user that the session could not be secured.
+ However, if a user agent that supports S/MIME receives a request with
+ an unsecured body, it SHOULD NOT respond with a secured body, but if
+ it expects S/MIME from the sender (for example, because the sender's
+ From header field value corresponds to an identity on its keychain),
+ the UAS SHOULD notify its user that the session could not be secured.
+
+ A number of conditions that arise in the previous text call for the
+ notification of the user when an anomalous certificate-management
+ event occurs. Users might well ask what they should do under these
+ circumstances. First and foremost, an unexpected change in a
+ certificate, or an absence of security when security is expected, are
+
+
+
+Rosenberg, et. al. Standards Track [Page 204]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ causes for caution but not necessarily indications that an attack is
+ in progress. Users might abort any connection attempt or refuse a
+ connection request they have received; in telephony parlance, they
+ could hang up and call back. Users may wish to find an alternate
+ means to contact the other party and confirm that their key has
+ legitimately changed. Note that users are sometimes compelled to
+ change their certificates, for example when they suspect that the
+ secrecy of their private key has been compromised. When their
+ private key is no longer private, users must legitimately generate a
+ new key and re-establish trust with any users that held their old
+ key.
+
+ Finally, if during the course of a dialog a UA receives a certificate
+ in a CMS SignedData message that does not correspond with the
+ certificates previously exchanged during a dialog, the UA MUST notify
+ its user of the change, preferably in terms that indicate that this
+ is a potential security breach.
+
+23.3 Securing MIME bodies
+
+ There are two types of secure MIME bodies that are of interest to
+ SIP: use of these bodies should follow the S/MIME specification [24]
+ with a few variations.
+
+ o "multipart/signed" MUST be used only with CMS detached
+ signatures.
+
+ This allows backwards compatibility with non-S/MIME-
+ compliant recipients.
+
+ o S/MIME bodies SHOULD have a Content-Disposition header field,
+ and the value of the "handling" parameter SHOULD be "required."
+
+ o If a UAC has no certificate on its keyring associated with the
+ address-of-record to which it wants to send a request, it
+ cannot send an encrypted "application/pkcs7-mime" MIME message.
+ UACs MAY send an initial request such as an OPTIONS message
+ with a CMS detached signature in order to solicit the
+ certificate of the remote side (the signature SHOULD be over a
+ "message/sip" body of the type described in Section 23.4).
+
+ Note that future standardization work on S/MIME may define
+ non-certificate based keys.
+
+ o Senders of S/MIME bodies SHOULD use the "SMIMECapabilities"
+ (see Section 2.5.2 of [24]) attribute to express their
+ capabilities and preferences for further communications. Note
+ especially that senders MAY use the "preferSignedData"
+
+
+
+Rosenberg, et. al. Standards Track [Page 205]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ capability to encourage receivers to respond with CMS
+ SignedData messages (for example, when sending an OPTIONS
+ request as described above).
+
+ o S/MIME implementations MUST at a minimum support SHA1 as a
+ digital signature algorithm, and 3DES as an encryption
+ algorithm. All other signature and encryption algorithms MAY
+ be supported. Implementations can negotiate support for these
+ algorithms with the "SMIMECapabilities" attribute.
+
+ o Each S/MIME body in a SIP message SHOULD be signed with only
+ one certificate. If a UA receives a message with multiple
+ signatures, the outermost signature should be treated as the
+ single certificate for this body. Parallel signatures SHOULD
+ NOT be used.
+
+ The following is an example of an encrypted S/MIME SDP body
+ within a SIP message:
+
+ INVITE sip:bob@biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ To: Bob <sip:bob@biloxi.com>
+ From: Alice <sip:alice@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710
+ CSeq: 314159 INVITE
+ Max-Forwards: 70
+ Contact: <sip:alice@pc33.atlanta.com>
+ Content-Type: application/pkcs7-mime; smime-type=enveloped-data;
+ name=smime.p7m
+ Content-Disposition: attachment; filename=smime.p7m
+ handling=required
+
+ *******************************************************
+ * Content-Type: application/sdp *
+ * *
+ * v=0 *
+ * o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com *
+ * s=- *
+ * t=0 0 *
+ * c=IN IP4 pc33.atlanta.com *
+ * m=audio 3456 RTP/AVP 0 1 3 99 *
+ * a=rtpmap:0 PCMU/8000 *
+ *******************************************************
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 206]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+23.4 SIP Header Privacy and Integrity using S/MIME: Tunneling SIP
+
+ As a means of providing some degree of end-to-end authentication,
+ integrity or confidentiality for SIP header fields, S/MIME can
+ encapsulate entire SIP messages within MIME bodies of type
+ "message/sip" and then apply MIME security to these bodies in the
+ same manner as typical SIP bodies. These encapsulated SIP requests
+ and responses do not constitute a separate dialog or transaction,
+ they are a copy of the "outer" message that is used to verify
+ integrity or to supply additional information.
+
+ If a UAS receives a request that contains a tunneled "message/sip"
+ S/MIME body, it SHOULD include a tunneled "message/sip" body in the
+ response with the same smime-type.
+
+ Any traditional MIME bodies (such as SDP) SHOULD be attached to the
+ "inner" message so that they can also benefit from S/MIME security.
+ Note that "message/sip" bodies can be sent as a part of a MIME
+ "multipart/mixed" body if any unsecured MIME types should also be
+ transmitted in a request.
+
+23.4.1 Integrity and Confidentiality Properties of SIP Headers
+
+ When the S/MIME integrity or confidentiality mechanisms are used,
+ there may be discrepancies between the values in the "inner" message
+ and values in the "outer" message. The rules for handling any such
+ differences for all of the header fields described in this document
+ are given in this section.
+
+ Note that for the purposes of loose timestamping, all SIP messages
+ that tunnel "message/sip" SHOULD contain a Date header in both the
+ "inner" and "outer" headers.
+
+23.4.1.1 Integrity
+
+ Whenever integrity checks are performed, the integrity of a header
+ field should be determined by matching the value of the header field
+ in the signed body with that in the "outer" messages using the
+ comparison rules of SIP as described in 20.
+
+ Header fields that can be legitimately modified by proxy servers are:
+ Request-URI, Via, Record-Route, Route, Max-Forwards, and Proxy-
+ Authorization. If these header fields are not intact end-to-end,
+ implementations SHOULD NOT consider this a breach of security.
+ Changes to any other header fields defined in this document
+ constitute an integrity violation; users MUST be notified of a
+ discrepancy.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 207]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+23.4.1.2 Confidentiality
+
+ When messages are encrypted, header fields may be included in the
+ encrypted body that are not present in the "outer" message.
+
+ Some header fields must always have a plaintext version because they
+ are required header fields in requests and responses - these include:
+
+ To, From, Call-ID, CSeq, Contact. While it is probably not useful to
+ provide an encrypted alternative for the Call-ID, CSeq, or Contact,
+ providing an alternative to the information in the "outer" To or From
+ is permitted. Note that the values in an encrypted body are not used
+ for the purposes of identifying transactions or dialogs - they are
+ merely informational. If the From header field in an encrypted body
+ differs from the value in the "outer" message, the value within the
+ encrypted body SHOULD be displayed to the user, but MUST NOT be used
+ in the "outer" header fields of any future messages.
+
+ Primarily, a user agent will want to encrypt header fields that have
+ an end-to-end semantic, including: Subject, Reply-To, Organization,
+ Accept, Accept-Encoding, Accept-Language, Alert-Info, Error-Info,
+ Authentication-Info, Expires, In-Reply-To, Require, Supported,
+ Unsupported, Retry-After, User-Agent, Server, and Warning. If any of
+ these header fields are present in an encrypted body, they should be
+ used instead of any "outer" header fields, whether this entails
+ displaying the header field values to users or setting internal
+ states in the UA. They SHOULD NOT however be used in the "outer"
+ headers of any future messages.
+
+ If present, the Date header field MUST always be the same in the
+ "inner" and "outer" headers.
+
+ Since MIME bodies are attached to the "inner" message,
+ implementations will usually encrypt MIME-specific header fields,
+ including: MIME-Version, Content-Type, Content-Length, Content-
+ Language, Content-Encoding and Content-Disposition. The "outer"
+ message will have the proper MIME header fields for S/MIME bodies.
+ These header fields (and any MIME bodies they preface) should be
+ treated as normal MIME header fields and bodies received in a SIP
+ message.
+
+ It is not particularly useful to encrypt the following header fields:
+ Min-Expires, Timestamp, Authorization, Priority, and WWW-
+ Authenticate. This category also includes those header fields that
+ can be changed by proxy servers (described in the preceding section).
+ UAs SHOULD never include these in an "inner" message if they are not
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 208]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ included in the "outer" message. UAs that receive any of these
+ header fields in an encrypted body SHOULD ignore the encrypted
+ values.
+
+ Note that extensions to SIP may define additional header fields; the
+ authors of these extensions should describe the integrity and
+ confidentiality properties of such header fields. If a SIP UA
+ encounters an unknown header field with an integrity violation, it
+ MUST ignore the header field.
+
+23.4.2 Tunneling Integrity and Authentication
+
+ Tunneling SIP messages within S/MIME bodies can provide integrity for
+ SIP header fields if the header fields that the sender wishes to
+ secure are replicated in a "message/sip" MIME body signed with a CMS
+ detached signature.
+
+ Provided that the "message/sip" body contains at least the
+ fundamental dialog identifiers (To, From, Call-ID, CSeq), then a
+ signed MIME body can provide limited authentication. At the very
+ least, if the certificate used to sign the body is unknown to the
+ recipient and cannot be verified, the signature can be used to
+ ascertain that a later request in a dialog was transmitted by the
+ same certificate-holder that initiated the dialog. If the recipient
+ of the signed MIME body has some stronger incentive to trust the
+ certificate (they were able to validate it, they acquired it from a
+ trusted repository, or they have used it frequently) then the
+ signature can be taken as a stronger assertion of the identity of the
+ subject of the certificate.
+
+ In order to eliminate possible confusions about the addition or
+ subtraction of entire header fields, senders SHOULD replicate all
+ header fields from the request within the signed body. Any message
+ bodies that require integrity protection MUST be attached to the
+ "inner" message.
+
+ If a Date header is present in a message with a signed body, the
+ recipient SHOULD compare the header field value with its own internal
+ clock, if applicable. If a significant time discrepancy is detected
+ (on the order of an hour or more), the user agent SHOULD alert the
+ user to the anomaly, and note that it is a potential security breach.
+
+ If an integrity violation in a message is detected by its recipient,
+ the message MAY be rejected with a 403 (Forbidden) response if it is
+ a request, or any existing dialog MAY be terminated. UAs SHOULD
+ notify users of this circumstance and request explicit guidance on
+ how to proceed.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 209]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The following is an example of the use of a tunneled "message/sip"
+ body:
+
+ INVITE sip:bob@biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ To: Bob <sip:bob@biloxi.com>
+ From: Alice <sip:alice@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710
+ CSeq: 314159 INVITE
+ Max-Forwards: 70
+ Date: Thu, 21 Feb 2002 13:02:03 GMT
+ Contact: <sip:alice@pc33.atlanta.com>
+ Content-Type: multipart/signed;
+ protocol="application/pkcs7-signature";
+ micalg=sha1; boundary=boundary42
+ Content-Length: 568
+
+ --boundary42
+ Content-Type: message/sip
+
+ INVITE sip:bob@biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ To: Bob <bob@biloxi.com>
+ From: Alice <alice@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710
+ CSeq: 314159 INVITE
+ Max-Forwards: 70
+ Date: Thu, 21 Feb 2002 13:02:03 GMT
+ Contact: <sip:alice@pc33.atlanta.com>
+ Content-Type: application/sdp
+ Content-Length: 147
+
+ v=0
+ o=UserA 2890844526 2890844526 IN IP4 here.com
+ s=Session SDP
+ c=IN IP4 pc33.atlanta.com
+ t=0 0
+ m=audio 49172 RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+
+ --boundary42
+ Content-Type: application/pkcs7-signature; name=smime.p7s
+ Content-Transfer-Encoding: base64
+ Content-Disposition: attachment; filename=smime.p7s;
+ handling=required
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 210]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ ghyHhHUujhJhjH77n8HHGTrfvbnj756tbB9HG4VQpfyF467GhIGfHfYT6
+ 4VQpfyF467GhIGfHfYT6jH77n8HHGghyHhHUujhJh756tbB9HGTrfvbnj
+ n8HHGTrfvhJhjH776tbB9HG4VQbnj7567GhIGfHfYT6ghyHhHUujpfyF4
+ 7GhIGfHfYT64VQbnj756
+
+ --boundary42-
+
+23.4.3 Tunneling Encryption
+
+ It may also be desirable to use this mechanism to encrypt a
+ "message/sip" MIME body within a CMS EnvelopedData message S/MIME
+ body, but in practice, most header fields are of at least some use to
+ the network; the general use of encryption with S/MIME is to secure
+ message bodies like SDP rather than message headers. Some
+ informational header fields, such as the Subject or Organization
+ could perhaps warrant end-to-end security. Headers defined by future
+ SIP applications might also require obfuscation.
+
+ Another possible application of encrypting header fields is selective
+ anonymity. A request could be constructed with a From header field
+ that contains no personal information (for example,
+ sip:anonymous@anonymizer.invalid). However, a second From header
+ field containing the genuine address-of-record of the originator
+ could be encrypted within a "message/sip" MIME body where it will
+ only be visible to the endpoints of a dialog.
+
+ Note that if this mechanism is used for anonymity, the From header
+ field will no longer be usable by the recipient of a message as an
+ index to their certificate keychain for retrieving the proper
+ S/MIME key to associated with the sender. The message must first
+ be decrypted, and the "inner" From header field MUST be used as an
+ index.
+
+ In order to provide end-to-end integrity, encrypted "message/sip"
+ MIME bodies SHOULD be signed by the sender. This creates a
+ "multipart/signed" MIME body that contains an encrypted body and a
+ signature, both of type "application/pkcs7-mime".
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 211]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ In the following example, of an encrypted and signed message, the
+ text boxed in asterisks ("*") is encrypted:
+
+ INVITE sip:bob@biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ To: Bob <sip:bob@biloxi.com>
+ From: Anonymous <sip:anonymous@atlanta.com>;tag=1928301774
+ Call-ID: a84b4c76e66710
+ CSeq: 314159 INVITE
+ Max-Forwards: 70
+ Date: Thu, 21 Feb 2002 13:02:03 GMT
+ Contact: <sip:pc33.atlanta.com>
+ Content-Type: multipart/signed;
+ protocol="application/pkcs7-signature";
+ micalg=sha1; boundary=boundary42
+ Content-Length: 568
+
+ --boundary42
+ Content-Type: application/pkcs7-mime; smime-type=enveloped-data;
+ name=smime.p7m
+ Content-Transfer-Encoding: base64
+ Content-Disposition: attachment; filename=smime.p7m
+ handling=required
+ Content-Length: 231
+
+ ***********************************************************
+ * Content-Type: message/sip *
+ * *
+ * INVITE sip:bob@biloxi.com SIP/2.0 *
+ * Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8 *
+ * To: Bob <bob@biloxi.com> *
+ * From: Alice <alice@atlanta.com>;tag=1928301774 *
+ * Call-ID: a84b4c76e66710 *
+ * CSeq: 314159 INVITE *
+ * Max-Forwards: 70 *
+ * Date: Thu, 21 Feb 2002 13:02:03 GMT *
+ * Contact: <sip:alice@pc33.atlanta.com> *
+ * *
+ * Content-Type: application/sdp *
+ * *
+ * v=0 *
+ * o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com *
+ * s=Session SDP *
+ * t=0 0 *
+ * c=IN IP4 pc33.atlanta.com *
+ * m=audio 3456 RTP/AVP 0 1 3 99 *
+ * a=rtpmap:0 PCMU/8000 *
+ ***********************************************************
+
+
+
+Rosenberg, et. al. Standards Track [Page 212]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ --boundary42
+ Content-Type: application/pkcs7-signature; name=smime.p7s
+ Content-Transfer-Encoding: base64
+ Content-Disposition: attachment; filename=smime.p7s;
+ handling=required
+
+ ghyHhHUujhJhjH77n8HHGTrfvbnj756tbB9HG4VQpfyF467GhIGfHfYT6
+ 4VQpfyF467GhIGfHfYT6jH77n8HHGghyHhHUujhJh756tbB9HGTrfvbnj
+ n8HHGTrfvhJhjH776tbB9HG4VQbnj7567GhIGfHfYT6ghyHhHUujpfyF4
+ 7GhIGfHfYT64VQbnj756
+
+ --boundary42-
+
+24 Examples
+
+ In the following examples, we often omit the message body and the
+ corresponding Content-Length and Content-Type header fields for
+ brevity.
+
+24.1 Registration
+
+ Bob registers on start-up. The message flow is shown in Figure 9.
+ Note that the authentication usually required for registration is not
+ shown for simplicity.
+
+ biloxi.com Bob's
+ registrar softphone
+ | |
+ | REGISTER F1 |
+ |<---------------|
+ | 200 OK F2 |
+ |--------------->|
+
+ Figure 9: SIP Registration Example
+
+ F1 REGISTER Bob -> Registrar
+
+ REGISTER sip:registrar.biloxi.com SIP/2.0
+ Via: SIP/2.0/UDP bobspc.biloxi.com:5060;branch=z9hG4bKnashds7
+ Max-Forwards: 70
+ To: Bob <sip:bob@biloxi.com>
+ From: Bob <sip:bob@biloxi.com>;tag=456248
+ Call-ID: 843817637684230@998sdasdh09
+ CSeq: 1826 REGISTER
+ Contact: <sip:bob@192.0.2.4>
+ Expires: 7200
+ Content-Length: 0
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 213]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The registration expires after two hours. The registrar responds
+ with a 200 OK:
+
+ F2 200 OK Registrar -> Bob
+
+ SIP/2.0 200 OK
+ Via: SIP/2.0/UDP bobspc.biloxi.com:5060;branch=z9hG4bKnashds7
+ ;received=192.0.2.4
+ To: Bob <sip:bob@biloxi.com>;tag=2493k59kd
+ From: Bob <sip:bob@biloxi.com>;tag=456248
+ Call-ID: 843817637684230@998sdasdh09
+ CSeq: 1826 REGISTER
+ Contact: <sip:bob@192.0.2.4>
+ Expires: 7200
+ Content-Length: 0
+
+24.2 Session Setup
+
+ This example contains the full details of the example session setup
+ in Section 4. The message flow is shown in Figure 1. Note that
+ these flows show the minimum required set of header fields - some
+ other header fields such as Allow and Supported would normally be
+ present.
+
+F1 INVITE Alice -> atlanta.com proxy
+
+INVITE sip:bob@biloxi.com SIP/2.0
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+Max-Forwards: 70
+To: Bob <sip:bob@biloxi.com>
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Contact: <sip:alice@pc33.atlanta.com>
+Content-Type: application/sdp
+Content-Length: 142
+
+(Alice's SDP not shown)
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 214]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+F2 100 Trying atlanta.com proxy -> Alice
+
+SIP/2.0 100 Trying
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Content-Length: 0
+
+F3 INVITE atlanta.com proxy -> biloxi.com proxy
+
+INVITE sip:bob@biloxi.com SIP/2.0
+Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+Max-Forwards: 69
+To: Bob <sip:bob@biloxi.com>
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Contact: <sip:alice@pc33.atlanta.com>
+Content-Type: application/sdp
+Content-Length: 142
+
+(Alice's SDP not shown)
+
+F4 100 Trying biloxi.com proxy -> atlanta.com proxy
+
+SIP/2.0 100 Trying
+Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
+ ;received=192.0.2.2
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Content-Length: 0
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 215]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+F5 INVITE biloxi.com proxy -> Bob
+
+INVITE sip:bob@192.0.2.4 SIP/2.0
+Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
+Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
+ ;received=192.0.2.2
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+Max-Forwards: 68
+To: Bob <sip:bob@biloxi.com>
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Contact: <sip:alice@pc33.atlanta.com>
+Content-Type: application/sdp
+Content-Length: 142
+
+(Alice's SDP not shown)
+
+F6 180 Ringing Bob -> biloxi.com proxy
+
+SIP/2.0 180 Ringing
+Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
+ ;received=192.0.2.3
+Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
+ ;received=192.0.2.2
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+Contact: <sip:bob@192.0.2.4>
+CSeq: 314159 INVITE
+Content-Length: 0
+
+F7 180 Ringing biloxi.com proxy -> atlanta.com proxy
+
+SIP/2.0 180 Ringing
+Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
+ ;received=192.0.2.2
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+Contact: <sip:bob@192.0.2.4>
+CSeq: 314159 INVITE
+Content-Length: 0
+
+
+
+Rosenberg, et. al. Standards Track [Page 216]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+F8 180 Ringing atlanta.com proxy -> Alice
+
+SIP/2.0 180 Ringing
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+Contact: <sip:bob@192.0.2.4>
+CSeq: 314159 INVITE
+Content-Length: 0
+
+F9 200 OK Bob -> biloxi.com proxy
+
+SIP/2.0 200 OK
+Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
+ ;received=192.0.2.3
+Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
+ ;received=192.0.2.2
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Contact: <sip:bob@192.0.2.4>
+Content-Type: application/sdp
+Content-Length: 131
+
+(Bob's SDP not shown)
+
+F10 200 OK biloxi.com proxy -> atlanta.com proxy
+
+SIP/2.0 200 OK
+Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
+ ;received=192.0.2.2
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Contact: <sip:bob@192.0.2.4>
+Content-Type: application/sdp
+Content-Length: 131
+
+(Bob's SDP not shown)
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 217]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+F11 200 OK atlanta.com proxy -> Alice
+
+SIP/2.0 200 OK
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
+ ;received=192.0.2.1
+To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 INVITE
+Contact: <sip:bob@192.0.2.4>
+Content-Type: application/sdp
+Content-Length: 131
+
+(Bob's SDP not shown)
+
+F12 ACK Alice -> Bob
+
+ACK sip:bob@192.0.2.4 SIP/2.0
+Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds9
+Max-Forwards: 70
+To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+From: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 314159 ACK
+Content-Length: 0
+
+ The media session between Alice and Bob is now established.
+
+ Bob hangs up first. Note that Bob's SIP phone maintains its own CSeq
+ numbering space, which, in this example, begins with 231. Since Bob
+ is making the request, the To and From URIs and tags have been
+ swapped.
+
+F13 BYE Bob -> Alice
+
+BYE sip:alice@pc33.atlanta.com SIP/2.0
+Via: SIP/2.0/UDP 192.0.2.4;branch=z9hG4bKnashds10
+Max-Forwards: 70
+From: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+To: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 231 BYE
+Content-Length: 0
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 218]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+F14 200 OK Alice -> Bob
+
+SIP/2.0 200 OK
+Via: SIP/2.0/UDP 192.0.2.4;branch=z9hG4bKnashds10
+From: Bob <sip:bob@biloxi.com>;tag=a6c85cf
+To: Alice <sip:alice@atlanta.com>;tag=1928301774
+Call-ID: a84b4c76e66710
+CSeq: 231 BYE
+Content-Length: 0
+
+ The SIP Call Flows document [40] contains further examples of SIP
+ messages.
+
+25 Augmented BNF for the SIP Protocol
+
+ All of the mechanisms specified in this document are described in
+ both prose and an augmented Backus-Naur Form (BNF) defined in RFC
+ 2234 [10]. Section 6.1 of RFC 2234 defines a set of core rules that
+ are used by this specification, and not repeated here. Implementers
+ need to be familiar with the notation and content of RFC 2234 in
+ order to understand this specification. Certain basic rules are in
+ uppercase, such as SP, LWS, HTAB, CRLF, DIGIT, ALPHA, etc. Angle
+ brackets are used within definitions to clarify the use of rule
+ names.
+
+ The use of square brackets is redundant syntactically. It is used as
+ a semantic hint that the specific parameter is optional to use.
+
+25.1 Basic Rules
+
+ The following rules are used throughout this specification to
+ describe basic parsing constructs. The US-ASCII coded character set
+ is defined by ANSI X3.4-1986.
+
+ alphanum = ALPHA / DIGIT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 219]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Several rules are incorporated from RFC 2396 [5] but are updated to
+ make them compliant with RFC 2234 [10]. These include:
+
+ reserved = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+"
+ / "$" / ","
+ unreserved = alphanum / mark
+ mark = "-" / "_" / "." / "!" / "~" / "*" / "'"
+ / "(" / ")"
+ escaped = "%" HEXDIG HEXDIG
+
+ SIP header field values can be folded onto multiple lines if the
+ continuation line begins with a space or horizontal tab. All linear
+ white space, including folding, has the same semantics as SP. A
+ recipient MAY replace any linear white space with a single SP before
+ interpreting the field value or forwarding the message downstream.
+ This is intended to behave exactly as HTTP/1.1 as described in RFC
+ 2616 [8]. The SWS construct is used when linear white space is
+ optional, generally between tokens and separators.
+
+ LWS = [*WSP CRLF] 1*WSP ; linear whitespace
+ SWS = [LWS] ; sep whitespace
+
+ To separate the header name from the rest of value, a colon is used,
+ which, by the above rule, allows whitespace before, but no line
+ break, and whitespace after, including a linebreak. The HCOLON
+ defines this construct.
+
+ HCOLON = *( SP / HTAB ) ":" SWS
+
+ The TEXT-UTF8 rule is only used for descriptive field contents and
+ values that are not intended to be interpreted by the message parser.
+ Words of *TEXT-UTF8 contain characters from the UTF-8 charset (RFC
+ 2279 [7]). The TEXT-UTF8-TRIM rule is used for descriptive field
+ contents that are n t quoted strings, where leading and trailing LWS
+ is not meaningful. In this regard, SIP differs from HTTP, which uses
+ the ISO 8859-1 character set.
+
+ TEXT-UTF8-TRIM = 1*TEXT-UTF8char *(*LWS TEXT-UTF8char)
+ TEXT-UTF8char = %x21-7E / UTF8-NONASCII
+ UTF8-NONASCII = %xC0-DF 1UTF8-CONT
+ / %xE0-EF 2UTF8-CONT
+ / %xF0-F7 3UTF8-CONT
+ / %xF8-Fb 4UTF8-CONT
+ / %xFC-FD 5UTF8-CONT
+ UTF8-CONT = %x80-BF
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 220]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ A CRLF is allowed in the definition of TEXT-UTF8-TRIM only as part of
+ a header field continuation. It is expected that the folding LWS
+ will be replaced with a single SP before interpretation of the TEXT-
+ UTF8-TRIM value.
+
+ Hexadecimal numeric characters are used in several protocol elements.
+ Some elements (authentication) force hex alphas to be lower case.
+
+ LHEX = DIGIT / %x61-66 ;lowercase a-f
+
+ Many SIP header field values consist of words separated by LWS or
+ special characters. Unless otherwise stated, tokens are case-
+ insensitive. These special characters MUST be in a quoted string to
+ be used within a parameter value. The word construct is used in
+ Call-ID to allow most separators to be used.
+
+ token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
+ / "_" / "+" / "`" / "'" / "~" )
+ separators = "(" / ")" / "<" / ">" / "@" /
+ "," / ";" / ":" / "\" / DQUOTE /
+ "/" / "[" / "]" / "?" / "=" /
+ "{" / "}" / SP / HTAB
+ word = 1*(alphanum / "-" / "." / "!" / "%" / "*" /
+ "_" / "+" / "`" / "'" / "~" /
+ "(" / ")" / "<" / ">" /
+ ":" / "\" / DQUOTE /
+ "/" / "[" / "]" / "?" /
+ "{" / "}" )
+
+ When tokens are used or separators are used between elements,
+ whitespace is often allowed before or after these characters:
+
+ STAR = SWS "*" SWS ; asterisk
+ SLASH = SWS "/" SWS ; slash
+ EQUAL = SWS "=" SWS ; equal
+ LPAREN = SWS "(" SWS ; left parenthesis
+ RPAREN = SWS ")" SWS ; right parenthesis
+ RAQUOT = ">" SWS ; right angle quote
+ LAQUOT = SWS "<"; left angle quote
+ COMMA = SWS "," SWS ; comma
+ SEMI = SWS ";" SWS ; semicolon
+ COLON = SWS ":" SWS ; colon
+ LDQUOT = SWS DQUOTE; open double quotation mark
+ RDQUOT = DQUOTE SWS ; close double quotation mark
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 221]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Comments can be included in some SIP header fields by surrounding the
+ comment text with parentheses. Comments are only allowed in fields
+ containing "comment" as part of their field value definition. In all
+ other fields, parentheses are considered part of the field value.
+
+ comment = LPAREN *(ctext / quoted-pair / comment) RPAREN
+ ctext = %x21-27 / %x2A-5B / %x5D-7E / UTF8-NONASCII
+ / LWS
+
+ ctext includes all chars except left and right parens and backslash.
+ A string of text is parsed as a single word if it is quoted using
+ double-quote marks. In quoted strings, quotation marks (") and
+ backslashes (\) need to be escaped.
+
+ quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
+ qdtext = LWS / %x21 / %x23-5B / %x5D-7E
+ / UTF8-NONASCII
+
+ The backslash character ("\") MAY be used as a single-character
+ quoting mechanism only within quoted-string and comment constructs.
+ Unlike HTTP/1.1, the characters CR and LF cannot be escaped by this
+ mechanism to avoid conflict with line folding and header separation.
+
+quoted-pair = "\" (%x00-09 / %x0B-0C
+ / %x0E-7F)
+
+SIP-URI = "sip:" [ userinfo ] hostport
+ uri-parameters [ headers ]
+SIPS-URI = "sips:" [ userinfo ] hostport
+ uri-parameters [ headers ]
+userinfo = ( user / telephone-subscriber ) [ ":" password ] "@"
+user = 1*( unreserved / escaped / user-unreserved )
+user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
+password = *( unreserved / escaped /
+ "&" / "=" / "+" / "$" / "," )
+hostport = host [ ":" port ]
+host = hostname / IPv4address / IPv6reference
+hostname = *( domainlabel "." ) toplabel [ "." ]
+domainlabel = alphanum
+ / alphanum *( alphanum / "-" ) alphanum
+toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 222]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
+IPv6reference = "[" IPv6address "]"
+IPv6address = hexpart [ ":" IPv4address ]
+hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
+hexseq = hex4 *( ":" hex4)
+hex4 = 1*4HEXDIG
+port = 1*DIGIT
+
+ The BNF for telephone-subscriber can be found in RFC 2806 [9]. Note,
+ however, that any characters allowed there that are not allowed in
+ the user part of the SIP URI MUST be escaped.
+
+uri-parameters = *( ";" uri-parameter)
+uri-parameter = transport-param / user-param / method-param
+ / ttl-param / maddr-param / lr-param / other-param
+transport-param = "transport="
+ ( "udp" / "tcp" / "sctp" / "tls"
+ / other-transport)
+other-transport = token
+user-param = "user=" ( "phone" / "ip" / other-user)
+other-user = token
+method-param = "method=" Method
+ttl-param = "ttl=" ttl
+maddr-param = "maddr=" host
+lr-param = "lr"
+other-param = pname [ "=" pvalue ]
+pname = 1*paramchar
+pvalue = 1*paramchar
+paramchar = param-unreserved / unreserved / escaped
+param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
+
+headers = "?" header *( "&" header )
+header = hname "=" hvalue
+hname = 1*( hnv-unreserved / unreserved / escaped )
+hvalue = *( hnv-unreserved / unreserved / escaped )
+hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
+
+SIP-message = Request / Response
+Request = Request-Line
+ *( message-header )
+ CRLF
+ [ message-body ]
+Request-Line = Method SP Request-URI SP SIP-Version CRLF
+Request-URI = SIP-URI / SIPS-URI / absoluteURI
+absoluteURI = scheme ":" ( hier-part / opaque-part )
+hier-part = ( net-path / abs-path ) [ "?" query ]
+net-path = "//" authority [ abs-path ]
+abs-path = "/" path-segments
+
+
+
+Rosenberg, et. al. Standards Track [Page 223]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+opaque-part = uric-no-slash *uric
+uric = reserved / unreserved / escaped
+uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@"
+ / "&" / "=" / "+" / "$" / ","
+path-segments = segment *( "/" segment )
+segment = *pchar *( ";" param )
+param = *pchar
+pchar = unreserved / escaped /
+ ":" / "@" / "&" / "=" / "+" / "$" / ","
+scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+authority = srvr / reg-name
+srvr = [ [ userinfo "@" ] hostport ]
+reg-name = 1*( unreserved / escaped / "$" / ","
+ / ";" / ":" / "@" / "&" / "=" / "+" )
+query = *uric
+SIP-Version = "SIP" "/" 1*DIGIT "." 1*DIGIT
+
+message-header = (Accept
+ / Accept-Encoding
+ / Accept-Language
+ / Alert-Info
+ / Allow
+ / Authentication-Info
+ / Authorization
+ / Call-ID
+ / Call-Info
+ / Contact
+ / Content-Disposition
+ / Content-Encoding
+ / Content-Language
+ / Content-Length
+ / Content-Type
+ / CSeq
+ / Date
+ / Error-Info
+ / Expires
+ / From
+ / In-Reply-To
+ / Max-Forwards
+ / MIME-Version
+ / Min-Expires
+ / Organization
+ / Priority
+ / Proxy-Authenticate
+ / Proxy-Authorization
+ / Proxy-Require
+ / Record-Route
+ / Reply-To
+
+
+
+Rosenberg, et. al. Standards Track [Page 224]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ / Require
+ / Retry-After
+ / Route
+ / Server
+ / Subject
+ / Supported
+ / Timestamp
+ / To
+ / Unsupported
+ / User-Agent
+ / Via
+ / Warning
+ / WWW-Authenticate
+ / extension-header) CRLF
+
+INVITEm = %x49.4E.56.49.54.45 ; INVITE in caps
+ACKm = %x41.43.4B ; ACK in caps
+OPTIONSm = %x4F.50.54.49.4F.4E.53 ; OPTIONS in caps
+BYEm = %x42.59.45 ; BYE in caps
+CANCELm = %x43.41.4E.43.45.4C ; CANCEL in caps
+REGISTERm = %x52.45.47.49.53.54.45.52 ; REGISTER in caps
+Method = INVITEm / ACKm / OPTIONSm / BYEm
+ / CANCELm / REGISTERm
+ / extension-method
+extension-method = token
+Response = Status-Line
+ *( message-header )
+ CRLF
+ [ message-body ]
+
+Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+Status-Code = Informational
+ / Redirection
+ / Success
+ / Client-Error
+ / Server-Error
+ / Global-Failure
+ / extension-code
+extension-code = 3DIGIT
+Reason-Phrase = *(reserved / unreserved / escaped
+ / UTF8-NONASCII / UTF8-CONT / SP / HTAB)
+
+Informational = "100" ; Trying
+ / "180" ; Ringing
+ / "181" ; Call Is Being Forwarded
+ / "182" ; Queued
+ / "183" ; Session Progress
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 225]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Success = "200" ; OK
+
+Redirection = "300" ; Multiple Choices
+ / "301" ; Moved Permanently
+ / "302" ; Moved Temporarily
+ / "305" ; Use Proxy
+ / "380" ; Alternative Service
+
+Client-Error = "400" ; Bad Request
+ / "401" ; Unauthorized
+ / "402" ; Payment Required
+ / "403" ; Forbidden
+ / "404" ; Not Found
+ / "405" ; Method Not Allowed
+ / "406" ; Not Acceptable
+ / "407" ; Proxy Authentication Required
+ / "408" ; Request Timeout
+ / "410" ; Gone
+ / "413" ; Request Entity Too Large
+ / "414" ; Request-URI Too Large
+ / "415" ; Unsupported Media Type
+ / "416" ; Unsupported URI Scheme
+ / "420" ; Bad Extension
+ / "421" ; Extension Required
+ / "423" ; Interval Too Brief
+ / "480" ; Temporarily not available
+ / "481" ; Call Leg/Transaction Does Not Exist
+ / "482" ; Loop Detected
+ / "483" ; Too Many Hops
+ / "484" ; Address Incomplete
+ / "485" ; Ambiguous
+ / "486" ; Busy Here
+ / "487" ; Request Terminated
+ / "488" ; Not Acceptable Here
+ / "491" ; Request Pending
+ / "493" ; Undecipherable
+
+Server-Error = "500" ; Internal Server Error
+ / "501" ; Not Implemented
+ / "502" ; Bad Gateway
+ / "503" ; Service Unavailable
+ / "504" ; Server Time-out
+ / "505" ; SIP Version not supported
+ / "513" ; Message Too Large
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 226]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Global-Failure = "600" ; Busy Everywhere
+ / "603" ; Decline
+ / "604" ; Does not exist anywhere
+ / "606" ; Not Acceptable
+
+Accept = "Accept" HCOLON
+ [ accept-range *(COMMA accept-range) ]
+accept-range = media-range *(SEMI accept-param)
+media-range = ( "*/*"
+ / ( m-type SLASH "*" )
+ / ( m-type SLASH m-subtype )
+ ) *( SEMI m-parameter )
+accept-param = ("q" EQUAL qvalue) / generic-param
+qvalue = ( "0" [ "." 0*3DIGIT ] )
+ / ( "1" [ "." 0*3("0") ] )
+generic-param = token [ EQUAL gen-value ]
+gen-value = token / host / quoted-string
+
+Accept-Encoding = "Accept-Encoding" HCOLON
+ [ encoding *(COMMA encoding) ]
+encoding = codings *(SEMI accept-param)
+codings = content-coding / "*"
+content-coding = token
+
+Accept-Language = "Accept-Language" HCOLON
+ [ language *(COMMA language) ]
+language = language-range *(SEMI accept-param)
+language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
+
+Alert-Info = "Alert-Info" HCOLON alert-param *(COMMA alert-param)
+alert-param = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+
+Allow = "Allow" HCOLON [Method *(COMMA Method)]
+
+Authorization = "Authorization" HCOLON credentials
+credentials = ("Digest" LWS digest-response)
+ / other-response
+digest-response = dig-resp *(COMMA dig-resp)
+dig-resp = username / realm / nonce / digest-uri
+ / dresponse / algorithm / cnonce
+ / opaque / message-qop
+ / nonce-count / auth-param
+username = "username" EQUAL username-value
+username-value = quoted-string
+digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
+digest-uri-value = rquest-uri ; Equal to request-uri as specified
+ by HTTP/1.1
+message-qop = "qop" EQUAL qop-value
+
+
+
+Rosenberg, et. al. Standards Track [Page 227]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+cnonce = "cnonce" EQUAL cnonce-value
+cnonce-value = nonce-value
+nonce-count = "nc" EQUAL nc-value
+nc-value = 8LHEX
+dresponse = "response" EQUAL request-digest
+request-digest = LDQUOT 32LHEX RDQUOT
+auth-param = auth-param-name EQUAL
+ ( token / quoted-string )
+auth-param-name = token
+other-response = auth-scheme LWS auth-param
+ *(COMMA auth-param)
+auth-scheme = token
+
+Authentication-Info = "Authentication-Info" HCOLON ainfo
+ *(COMMA ainfo)
+ainfo = nextnonce / message-qop
+ / response-auth / cnonce
+ / nonce-count
+nextnonce = "nextnonce" EQUAL nonce-value
+response-auth = "rspauth" EQUAL response-digest
+response-digest = LDQUOT *LHEX RDQUOT
+
+Call-ID = ( "Call-ID" / "i" ) HCOLON callid
+callid = word [ "@" word ]
+
+Call-Info = "Call-Info" HCOLON info *(COMMA info)
+info = LAQUOT absoluteURI RAQUOT *( SEMI info-param)
+info-param = ( "purpose" EQUAL ( "icon" / "info"
+ / "card" / token ) ) / generic-param
+
+Contact = ("Contact" / "m" ) HCOLON
+ ( STAR / (contact-param *(COMMA contact-param)))
+contact-param = (name-addr / addr-spec) *(SEMI contact-params)
+name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
+addr-spec = SIP-URI / SIPS-URI / absoluteURI
+display-name = *(token LWS)/ quoted-string
+
+contact-params = c-p-q / c-p-expires
+ / contact-extension
+c-p-q = "q" EQUAL qvalue
+c-p-expires = "expires" EQUAL delta-seconds
+contact-extension = generic-param
+delta-seconds = 1*DIGIT
+
+Content-Disposition = "Content-Disposition" HCOLON
+ disp-type *( SEMI disp-param )
+disp-type = "render" / "session" / "icon" / "alert"
+ / disp-extension-token
+
+
+
+Rosenberg, et. al. Standards Track [Page 228]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+disp-param = handling-param / generic-param
+handling-param = "handling" EQUAL
+ ( "optional" / "required"
+ / other-handling )
+other-handling = token
+disp-extension-token = token
+
+Content-Encoding = ( "Content-Encoding" / "e" ) HCOLON
+ content-coding *(COMMA content-coding)
+
+Content-Language = "Content-Language" HCOLON
+ language-tag *(COMMA language-tag)
+language-tag = primary-tag *( "-" subtag )
+primary-tag = 1*8ALPHA
+subtag = 1*8ALPHA
+
+Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
+Content-Type = ( "Content-Type" / "c" ) HCOLON media-type
+media-type = m-type SLASH m-subtype *(SEMI m-parameter)
+m-type = discrete-type / composite-type
+discrete-type = "text" / "image" / "audio" / "video"
+ / "application" / extension-token
+composite-type = "message" / "multipart" / extension-token
+extension-token = ietf-token / x-token
+ietf-token = token
+x-token = "x-" token
+m-subtype = extension-token / iana-token
+iana-token = token
+m-parameter = m-attribute EQUAL m-value
+m-attribute = token
+m-value = token / quoted-string
+
+CSeq = "CSeq" HCOLON 1*DIGIT LWS Method
+
+Date = "Date" HCOLON SIP-date
+SIP-date = rfc1123-date
+rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+date1 = 2DIGIT SP month SP 4DIGIT
+ ; day month year (e.g., 02 Jun 1982)
+time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ ; 00:00:00 - 23:59:59
+wkday = "Mon" / "Tue" / "Wed"
+ / "Thu" / "Fri" / "Sat" / "Sun"
+month = "Jan" / "Feb" / "Mar" / "Apr"
+ / "May" / "Jun" / "Jul" / "Aug"
+ / "Sep" / "Oct" / "Nov" / "Dec"
+
+Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
+
+
+
+Rosenberg, et. al. Standards Track [Page 229]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+error-uri = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
+
+Expires = "Expires" HCOLON delta-seconds
+From = ( "From" / "f" ) HCOLON from-spec
+from-spec = ( name-addr / addr-spec )
+ *( SEMI from-param )
+from-param = tag-param / generic-param
+tag-param = "tag" EQUAL token
+
+In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
+
+Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT
+
+MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
+
+Min-Expires = "Min-Expires" HCOLON delta-seconds
+
+Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
+
+Priority = "Priority" HCOLON priority-value
+priority-value = "emergency" / "urgent" / "normal"
+ / "non-urgent" / other-priority
+other-priority = token
+
+Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
+challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
+ / other-challenge
+other-challenge = auth-scheme LWS auth-param
+ *(COMMA auth-param)
+digest-cln = realm / domain / nonce
+ / opaque / stale / algorithm
+ / qop-options / auth-param
+realm = "realm" EQUAL realm-value
+realm-value = quoted-string
+domain = "domain" EQUAL LDQUOT URI
+ *( 1*SP URI ) RDQUOT
+URI = absoluteURI / abs-path
+nonce = "nonce" EQUAL nonce-value
+nonce-value = quoted-string
+opaque = "opaque" EQUAL quoted-string
+stale = "stale" EQUAL ( "true" / "false" )
+algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
+ / token )
+qop-options = "qop" EQUAL LDQUOT qop-value
+ *("," qop-value) RDQUOT
+qop-value = "auth" / "auth-int" / token
+
+Proxy-Authorization = "Proxy-Authorization" HCOLON credentials
+
+
+
+Rosenberg, et. al. Standards Track [Page 230]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Proxy-Require = "Proxy-Require" HCOLON option-tag
+ *(COMMA option-tag)
+option-tag = token
+
+Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route)
+rec-route = name-addr *( SEMI rr-param )
+rr-param = generic-param
+
+Reply-To = "Reply-To" HCOLON rplyto-spec
+rplyto-spec = ( name-addr / addr-spec )
+ *( SEMI rplyto-param )
+rplyto-param = generic-param
+Require = "Require" HCOLON option-tag *(COMMA option-tag)
+
+Retry-After = "Retry-After" HCOLON delta-seconds
+ [ comment ] *( SEMI retry-param )
+
+retry-param = ("duration" EQUAL delta-seconds)
+ / generic-param
+
+Route = "Route" HCOLON route-param *(COMMA route-param)
+route-param = name-addr *( SEMI rr-param )
+
+Server = "Server" HCOLON server-val *(LWS server-val)
+server-val = product / comment
+product = token [SLASH product-version]
+product-version = token
+
+Subject = ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
+
+Supported = ( "Supported" / "k" ) HCOLON
+ [option-tag *(COMMA option-tag)]
+
+Timestamp = "Timestamp" HCOLON 1*(DIGIT)
+ [ "." *(DIGIT) ] [ LWS delay ]
+delay = *(DIGIT) [ "." *(DIGIT) ]
+
+To = ( "To" / "t" ) HCOLON ( name-addr
+ / addr-spec ) *( SEMI to-param )
+to-param = tag-param / generic-param
+
+Unsupported = "Unsupported" HCOLON option-tag *(COMMA option-tag)
+User-Agent = "User-Agent" HCOLON server-val *(LWS server-val)
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 231]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
+via-parm = sent-protocol LWS sent-by *( SEMI via-params )
+via-params = via-ttl / via-maddr
+ / via-received / via-branch
+ / via-extension
+via-ttl = "ttl" EQUAL ttl
+via-maddr = "maddr" EQUAL host
+via-received = "received" EQUAL (IPv4address / IPv6address)
+via-branch = "branch" EQUAL token
+via-extension = generic-param
+sent-protocol = protocol-name SLASH protocol-version
+ SLASH transport
+protocol-name = "SIP" / token
+protocol-version = token
+transport = "UDP" / "TCP" / "TLS" / "SCTP"
+ / other-transport
+sent-by = host [ COLON port ]
+ttl = 1*3DIGIT ; 0 to 255
+
+Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
+warning-value = warn-code SP warn-agent SP warn-text
+warn-code = 3DIGIT
+warn-agent = hostport / pseudonym
+ ; the name or pseudonym of the server adding
+ ; the Warning header, for use in debugging
+warn-text = quoted-string
+pseudonym = token
+
+WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
+
+extension-header = header-name HCOLON header-value
+header-name = token
+header-value = *(TEXT-UTF8char / UTF8-CONT / LWS)
+message-body = *OCTET
+
+26 Security Considerations: Threat Model and Security Usage
+ Recommendations
+
+ SIP is not an easy protocol to secure. Its use of intermediaries,
+ its multi-faceted trust relationships, its expected usage between
+ elements with no trust at all, and its user-to-user operation make
+ security far from trivial. Security solutions are needed that are
+ deployable today, without extensive coordination, in a wide variety
+ of environments and usages. In order to meet these diverse needs,
+ several distinct mechanisms applicable to different aspects and
+ usages of SIP will be required.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 232]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Note that the security of SIP signaling itself has no bearing on the
+ security of protocols used in concert with SIP such as RTP, or with
+ the security implications of any specific bodies SIP might carry
+ (although MIME security plays a substantial role in securing SIP).
+ Any media associated with a session can be encrypted end-to-end
+ independently of any associated SIP signaling. Media encryption is
+ outside the scope of this document.
+
+ The considerations that follow first examine a set of classic threat
+ models that broadly identify the security needs of SIP. The set of
+ security services required to address these threats is then detailed,
+ followed by an explanation of several security mechanisms that can be
+ used to provide these services. Next, the requirements for
+ implementers of SIP are enumerated, along with exemplary deployments
+ in which these security mechanisms could be used to improve the
+ security of SIP. Some notes on privacy conclude this section.
+
+26.1 Attacks and Threat Models
+
+ This section details some threats that should be common to most
+ deployments of SIP. These threats have been chosen specifically to
+ illustrate each of the security services that SIP requires.
+
+ The following examples by no means provide an exhaustive list of the
+ threats against SIP; rather, these are "classic" threats that
+ demonstrate the need for particular security services that can
+ potentially prevent whole categories of threats.
+
+ These attacks assume an environment in which attackers can
+ potentially read any packet on the network - it is anticipated that
+ SIP will frequently be used on the public Internet. Attackers on the
+ network may be able to modify packets (perhaps at some compromised
+ intermediary). Attackers may wish to steal services, eavesdrop on
+ communications, or disrupt sessions.
+
+26.1.1 Registration Hijacking
+
+ The SIP registration mechanism allows a user agent to identify itself
+ to a registrar as a device at which a user (designated by an address
+ of record) is located. A registrar assesses the identity asserted in
+ the From header field of a REGISTER message to determine whether this
+ request can modify the contact addresses associated with the
+ address-of-record in the To header field. While these two fields are
+ frequently the same, there are many valid deployments in which a
+ third-party may register contacts on a user's behalf.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 233]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The From header field of a SIP request, however, can be modified
+ arbitrarily by the owner of a UA, and this opens the door to
+ malicious registrations. An attacker that successfully impersonates
+ a party authorized to change contacts associated with an address-of-
+ record could, for example, de-register all existing contacts for a
+ URI and then register their own device as the appropriate contact
+ address, thereby directing all requests for the affected user to the
+ attacker's device.
+
+ This threat belongs to a family of threats that rely on the absence
+ of cryptographic assurance of a request's originator. Any SIP UAS
+ that represents a valuable service (a gateway that interworks SIP
+ requests with traditional telephone calls, for example) might want to
+ control access to its resources by authenticating requests that it
+ receives. Even end-user UAs, for example SIP phones, have an
+ interest in ascertaining the identities of originators of requests.
+
+ This threat demonstrates the need for security services that enable
+ SIP entities to authenticate the originators of requests.
+
+26.1.2 Impersonating a Server
+
+ The domain to which a request is destined is generally specified in
+ the Request-URI. UAs commonly contact a server in this domain
+ directly in order to deliver a request. However, there is always a
+ possibility that an attacker could impersonate the remote server, and
+ that the UA's request could be intercepted by some other party.
+
+ For example, consider a case in which a redirect server at one
+ domain, chicago.com, impersonates a redirect server at another
+ domain, biloxi.com. A user agent sends a request to biloxi.com, but
+ the redirect server at chicago.com answers with a forged response
+ that has appropriate SIP header fields for a response from
+ biloxi.com. The forged contact addresses in the redirection response
+ could direct the originating UA to inappropriate or insecure
+ resources, or simply prevent requests for biloxi.com from succeeding.
+
+ This family of threats has a vast membership, many of which are
+ critical. As a converse to the registration hijacking threat,
+ consider the case in which a registration sent to biloxi.com is
+ intercepted by chicago.com, which replies to the intercepted
+ registration with a forged 301 (Moved Permanently) response. This
+ response might seem to come from biloxi.com yet designate chicago.com
+ as the appropriate registrar. All future REGISTER requests from the
+ originating UA would then go to chicago.com.
+
+ Prevention of this threat requires a means by which UAs can
+ authenticate the servers to whom they send requests.
+
+
+
+Rosenberg, et. al. Standards Track [Page 234]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+26.1.3 Tampering with Message Bodies
+
+ As a matter of course, SIP UAs route requests through trusted proxy
+ servers. Regardless of how that trust is established (authentication
+ of proxies is discussed elsewhere in this section), a UA may trust a
+ proxy server to route a request, but not to inspect or possibly
+ modify the bodies contained in that request.
+
+ Consider a UA that is using SIP message bodies to communicate session
+ encryption keys for a media session. Although it trusts the proxy
+ server of the domain it is contacting to deliver signaling properly,
+ it may not want the administrators of that domain to be capable of
+ decrypting any subsequent media session. Worse yet, if the proxy
+ server were actively malicious, it could modify the session key,
+ either acting as a man-in-the-middle, or perhaps changing the
+ security characteristics requested by the originating UA.
+
+ This family of threats applies not only to session keys, but to most
+ conceivable forms of content carried end-to-end in SIP. These might
+ include MIME bodies that should be rendered to the user, SDP, or
+ encapsulated telephony signals, among others. Attackers might
+ attempt to modify SDP bodies, for example, in order to point RTP
+ media streams to a wiretapping device in order to eavesdrop on
+ subsequent voice communications.
+
+ Also note that some header fields in SIP are meaningful end-to-end,
+ for example, Subject. UAs might be protective of these header fields
+ as well as bodies (a malicious intermediary changing the Subject
+ header field might make an important request appear to be spam, for
+ example). However, since many header fields are legitimately
+ inspected or altered by proxy servers as a request is routed, not all
+ header fields should be secured end-to-end.
+
+ For these reasons, the UA might want to secure SIP message bodies,
+ and in some limited cases header fields, end-to-end. The security
+ services required for bodies include confidentiality, integrity, and
+ authentication. These end-to-end services should be independent of
+ the means used to secure interactions with intermediaries such as
+ proxy servers.
+
+26.1.4 Tearing Down Sessions
+
+ Once a dialog has been established by initial messaging, subsequent
+ requests can be sent that modify the state of the dialog and/or
+ session. It is critical that principals in a session can be certain
+ that such requests are not forged by attackers.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 235]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Consider a case in which a third-party attacker captures some initial
+ messages in a dialog shared by two parties in order to learn the
+ parameters of the session (To tag, From tag, and so forth) and then
+ inserts a BYE request into the session. The attacker could opt to
+ forge the request such that it seemed to come from either
+ participant. Once the BYE is received by its target, the session
+ will be torn down prematurely.
+
+ Similar mid-session threats include the transmission of forged re-
+ INVITEs that alter the session (possibly to reduce session security
+ or redirect media streams as part of a wiretapping attack).
+
+ The most effective countermeasure to this threat is the
+ authentication of the sender of the BYE. In this instance, the
+ recipient needs only know that the BYE came from the same party with
+ whom the corresponding dialog was established (as opposed to
+ ascertaining the absolute identity of the sender). Also, if the
+ attacker is unable to learn the parameters of the session due to
+ confidentiality, it would not be possible to forge the BYE. However,
+ some intermediaries (like proxy servers) will need to inspect those
+ parameters as the session is established.
+
+26.1.5 Denial of Service and Amplification
+
+ Denial-of-service attacks focus on rendering a particular network
+ element unavailable, usually by directing an excessive amount of
+ network traffic at its interfaces. A distributed denial-of-service
+ attack allows one network user to cause multiple network hosts to
+ flood a target host with a large amount of network traffic.
+
+ In many architectures, SIP proxy servers face the public Internet in
+ order to accept requests from worldwide IP endpoints. SIP creates a
+ number of potential opportunities for distributed denial-of-service
+ attacks that must be recognized and addressed by the implementers and
+ operators of SIP systems.
+
+ Attackers can create bogus requests that contain a falsified source
+ IP address and a corresponding Via header field that identify a
+ targeted host as the originator of the request and then send this
+ request to a large number of SIP network elements, thereby using
+ hapless SIP UAs or proxies to generate denial-of-service traffic
+ aimed at the target.
+
+ Similarly, attackers might use falsified Route header field values in
+ a request that identify the target host and then send such messages
+ to forking proxies that will amplify messaging sent to the target.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 236]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Record-Route could be used to similar effect when the attacker is
+ certain that the SIP dialog initiated by the request will result in
+ numerous transactions originating in the backwards direction.
+
+ A number of denial-of-service attacks open up if REGISTER requests
+ are not properly authenticated and authorized by registrars.
+ Attackers could de-register some or all users in an administrative
+ domain, thereby preventing these users from being invited to new
+ sessions. An attacker could also register a large number of contacts
+ designating the same host for a given address-of-record in order to
+ use the registrar and any associated proxy servers as amplifiers in a
+ denial-of-service attack. Attackers might also attempt to deplete
+ available memory and disk resources of a registrar by registering
+ huge numbers of bindings.
+
+ The use of multicast to transmit SIP requests can greatly increase
+ the potential for denial-of-service attacks.
+
+ These problems demonstrate a general need to define architectures
+ that minimize the risks of denial-of-service, and the need to be
+ mindful in recommendations for security mechanisms of this class of
+ attacks.
+
+26.2 Security Mechanisms
+
+ From the threats described above, we gather that the fundamental
+ security services required for the SIP protocol are: preserving the
+ confidentiality and integrity of messaging, preventing replay attacks
+ or message spoofing, providing for the authentication and privacy of
+ the participants in a session, and preventing denial-of-service
+ attacks. Bodies within SIP messages separately require the security
+ services of confidentiality, integrity, and authentication.
+
+ Rather than defining new security mechanisms specific to SIP, SIP
+ reuses wherever possible existing security models derived from the
+ HTTP and SMTP space.
+
+ Full encryption of messages provides the best means to preserve the
+ confidentiality of signaling - it can also guarantee that messages
+ are not modified by any malicious intermediaries. However, SIP
+ requests and responses cannot be naively encrypted end-to-end in
+ their entirety because message fields such as the Request-URI, Route,
+ and Via need to be visible to proxies in most network architectures
+ so that SIP requests are routed correctly. Note that proxy servers
+ need to modify some features of messages as well (such as adding Via
+ header field values) in order for SIP to function. Proxy servers
+ must therefore be trusted, to some degree, by SIP UAs. To this
+ purpose, low-layer security mechanisms for SIP are recommended, which
+
+
+
+Rosenberg, et. al. Standards Track [Page 237]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ encrypt the entire SIP requests or responses on the wire on a hop-
+ by-hop basis, and that allow endpoints to verify the identity of
+ proxy servers to whom they send requests.
+
+ SIP entities also have a need to identify one another in a secure
+ fashion. When a SIP endpoint asserts the identity of its user to a
+ peer UA or to a proxy server, that identity should in some way be
+ verifiable. A cryptographic authentication mechanism is provided in
+ SIP to address this requirement.
+
+ An independent security mechanism for SIP message bodies supplies an
+ alternative means of end-to-end mutual authentication, as well as
+ providing a limit on the degree to which user agents must trust
+ intermediaries.
+
+26.2.1 Transport and Network Layer Security
+
+ Transport or network layer security encrypts signaling traffic,
+ guaranteeing message confidentiality and integrity.
+
+ Oftentimes, certificates are used in the establishment of lower-layer
+ security, and these certificates can also be used to provide a means
+ of authentication in many architectures.
+
+ Two popular alternatives for providing security at the transport and
+ network layer are, respectively, TLS [25] and IPSec [26].
+
+ IPSec is a set of network-layer protocol tools that collectively can
+ be used as a secure replacement for traditional IP (Internet
+ Protocol). IPSec is most commonly used in architectures in which a
+ set of hosts or administrative domains have an existing trust
+ relationship with one another. IPSec is usually implemented at the
+ operating system level in a host, or on a security gateway that
+ provides confidentiality and integrity for all traffic it receives
+ from a particular interface (as in a VPN architecture). IPSec can
+ also be used on a hop-by-hop basis.
+
+ In many architectures IPSec does not require integration with SIP
+ applications; IPSec is perhaps best suited to deployments in which
+ adding security directly to SIP hosts would be arduous. UAs that
+ have a pre-shared keying relationship with their first-hop proxy
+ server are also good candidates to use IPSec. Any deployment of
+ IPSec for SIP would require an IPSec profile describing the protocol
+ tools that would be required to secure SIP. No such profile is given
+ in this document.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 238]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ TLS provides transport-layer security over connection-oriented
+ protocols (for the purposes of this document, TCP); "tls" (signifying
+ TLS over TCP) can be specified as the desired transport protocol
+ within a Via header field value or a SIP-URI. TLS is most suited to
+ architectures in which hop-by-hop security is required between hosts
+ with no pre-existing trust association. For example, Alice trusts
+ her local proxy server, which after a certificate exchange decides to
+ trust Bob's local proxy server, which Bob trusts, hence Bob and Alice
+ can communicate securely.
+
+ TLS must be tightly coupled with a SIP application. Note that
+ transport mechanisms are specified on a hop-by-hop basis in SIP, thus
+ a UA that sends requests over TLS to a proxy server has no assurance
+ that TLS will be used end-to-end.
+
+ The TLS_RSA_WITH_AES_128_CBC_SHA ciphersuite [6] MUST be supported at
+ a minimum by implementers when TLS is used in a SIP application. For
+ purposes of backwards compatibility, proxy servers, redirect servers,
+ and registrars SHOULD support TLS_RSA_WITH_3DES_EDE_CBC_SHA.
+ Implementers MAY also support any other ciphersuite.
+
+26.2.2 SIPS URI Scheme
+
+ The SIPS URI scheme adheres to the syntax of the SIP URI (described
+ in 19), although the scheme string is "sips" rather than "sip". The
+ semantics of SIPS are very different from the SIP URI, however. SIPS
+ allows resources to specify that they should be reached securely.
+
+ A SIPS URI can be used as an address-of-record for a particular user
+ - the URI by which the user is canonically known (on their business
+ cards, in the From header field of their requests, in the To header
+ field of REGISTER requests). When used as the Request-URI of a
+ request, the SIPS scheme signifies that each hop over which the
+ request is forwarded, until the request reaches the SIP entity
+ responsible for the domain portion of the Request-URI, must be
+ secured with TLS; once it reaches the domain in question it is
+ handled in accordance with local security and routing policy, quite
+ possibly using TLS for any last hop to a UAS. When used by the
+ originator of a request (as would be the case if they employed a SIPS
+ URI as the address-of-record of the target), SIPS dictates that the
+ entire request path to the target domain be so secured.
+
+ The SIPS scheme is applicable to many of the other ways in which SIP
+ URIs are used in SIP today in addition to the Request-URI, including
+ in addresses-of-record, contact addresses (the contents of Contact
+ headers, including those of REGISTER methods), and Route headers. In
+ each instance, the SIPS URI scheme allows these existing fields to
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 239]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ designate secure resources. The manner in which a SIPS URI is
+ dereferenced in any of these contexts has its own security properties
+ which are detailed in [4].
+
+ The use of SIPS in particular entails that mutual TLS authentication
+ SHOULD be employed, as SHOULD the ciphersuite
+ TLS_RSA_WITH_AES_128_CBC_SHA. Certificates received in the
+ authentication process SHOULD be validated with root certificates
+ held by the client; failure to validate a certificate SHOULD result
+ in the failure of the request.
+
+ Note that in the SIPS URI scheme, transport is independent of TLS,
+ and thus "sips:alice@atlanta.com;transport=tcp" and
+ "sips:alice@atlanta.com;transport=sctp" are both valid (although
+ note that UDP is not a valid transport for SIPS). The use of
+ "transport=tls" has consequently been deprecated, partly because
+ it was specific to a single hop of the request. This is a change
+ since RFC 2543.
+
+ Users that distribute a SIPS URI as an address-of-record may elect to
+ operate devices that refuse requests over insecure transports.
+
+26.2.3 HTTP Authentication
+
+ SIP provides a challenge capability, based on HTTP authentication,
+ that relies on the 401 and 407 response codes as well as header
+ fields for carrying challenges and credentials. Without significant
+ modification, the reuse of the HTTP Digest authentication scheme in
+ SIP allows for replay protection and one-way authentication.
+
+ The usage of Digest authentication in SIP is detailed in Section 22.
+
+26.2.4 S/MIME
+
+ As is discussed above, encrypting entire SIP messages end-to-end for
+ the purpose of confidentiality is not appropriate because network
+ intermediaries (like proxy servers) need to view certain header
+ fields in order to route messages correctly, and if these
+ intermediaries are excluded from security associations, then SIP
+ messages will essentially be non-routable.
+
+ However, S/MIME allows SIP UAs to encrypt MIME bodies within SIP,
+ securing these bodies end-to-end without affecting message headers.
+ S/MIME can provide end-to-end confidentiality and integrity for
+ message bodies, as well as mutual authentication. It is also
+ possible to use S/MIME to provide a form of integrity and
+ confidentiality for SIP header fields through SIP message tunneling.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 240]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The usage of S/MIME in SIP is detailed in Section 23.
+
+26.3 Implementing Security Mechanisms
+
+26.3.1 Requirements for Implementers of SIP
+
+ Proxy servers, redirect servers, and registrars MUST implement TLS,
+ and MUST support both mutual and one-way authentication. It is
+ strongly RECOMMENDED that UAs be capable initiating TLS; UAs MAY also
+ be capable of acting as a TLS server. Proxy servers, redirect
+ servers, and registrars SHOULD possess a site certificate whose
+ subject corresponds to their canonical hostname. UAs MAY have
+ certificates of their own for mutual authentication with TLS, but no
+ provisions are set forth in this document for their use. All SIP
+ elements that support TLS MUST have a mechanism for validating
+ certificates received during TLS negotiation; this entails possession
+ of one or more root certificates issued by certificate authorities
+ (preferably well-known distributors of site certificates comparable
+ to those that issue root certificates for web browsers).
+
+ All SIP elements that support TLS MUST also support the SIPS URI
+ scheme.
+
+ Proxy servers, redirect servers, registrars, and UAs MAY also
+ implement IPSec or other lower-layer security protocols.
+
+ When a UA attempts to contact a proxy server, redirect server, or
+ registrar, the UAC SHOULD initiate a TLS connection over which it
+ will send SIP messages. In some architectures, UASs MAY receive
+ requests over such TLS connections as well.
+
+ Proxy servers, redirect servers, registrars, and UAs MUST implement
+ Digest Authorization, encompassing all of the aspects required in 22.
+ Proxy servers, redirect servers, and registrars SHOULD be configured
+ with at least one Digest realm, and at least one "realm" string
+ supported by a given server SHOULD correspond to the server's
+ hostname or domainname.
+
+ UAs MAY support the signing and encrypting of MIME bodies, and
+ transference of credentials with S/MIME as described in Section 23.
+ If a UA holds one or more root certificates of certificate
+ authorities in order to validate certificates for TLS or IPSec, it
+ SHOULD be capable of reusing these to verify S/MIME certificates, as
+ appropriate. A UA MAY hold root certificates specifically for
+ validating S/MIME certificates.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 241]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Note that is it anticipated that future security extensions may
+ upgrade the normative strength associated with S/MIME as S/MIME
+ implementations appear and the problem space becomes better
+ understood.
+
+26.3.2 Security Solutions
+
+ The operation of these security mechanisms in concert can follow the
+ existing web and email security models to some degree. At a high
+ level, UAs authenticate themselves to servers (proxy servers,
+ redirect servers, and registrars) with a Digest username and
+ password; servers authenticate themselves to UAs one hop away, or to
+ another server one hop away (and vice versa), with a site certificate
+ delivered by TLS.
+
+ On a peer-to-peer level, UAs trust the network to authenticate one
+ another ordinarily; however, S/MIME can also be used to provide
+ direct authentication when the network does not, or if the network
+ itself is not trusted.
+
+ The following is an illustrative example in which these security
+ mechanisms are used by various UAs and servers to prevent the sorts
+ of threats described in Section 26.1. While implementers and network
+ administrators MAY follow the normative guidelines given in the
+ remainder of this section, these are provided only as example
+ implementations.
+
+26.3.2.1 Registration
+
+ When a UA comes online and registers with its local administrative
+ domain, it SHOULD establish a TLS connection with its registrar
+ (Section 10 describes how the UA reaches its registrar). The
+ registrar SHOULD offer a certificate to the UA, and the site
+ identified by the certificate MUST correspond with the domain in
+ which the UA intends to register; for example, if the UA intends to
+ register the address-of-record 'alice@atlanta.com', the site
+ certificate must identify a host within the atlanta.com domain (such
+ as sip.atlanta.com). When it receives the TLS Certificate message,
+ the UA SHOULD verify the certificate and inspect the site identified
+ by the certificate. If the certificate is invalid, revoked, or if it
+ does not identify the appropriate party, the UA MUST NOT send the
+ REGISTER message and otherwise proceed with the registration.
+
+ When a valid certificate has been provided by the registrar, the
+ UA knows that the registrar is not an attacker who might redirect
+ the UA, steal passwords, or attempt any similar attacks.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 242]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The UA then creates a REGISTER request that SHOULD be addressed to a
+ Request-URI corresponding to the site certificate received from the
+ registrar. When the UA sends the REGISTER request over the existing
+ TLS connection, the registrar SHOULD challenge the request with a 401
+ (Proxy Authentication Required) response. The "realm" parameter
+ within the Proxy-Authenticate header field of the response SHOULD
+ correspond to the domain previously given by the site certificate.
+ When the UAC receives the challenge, it SHOULD either prompt the user
+ for credentials or take an appropriate credential from a keyring
+ corresponding to the "realm" parameter in the challenge. The
+ username of this credential SHOULD correspond with the "userinfo"
+ portion of the URI in the To header field of the REGISTER request.
+ Once the Digest credentials have been inserted into an appropriate
+ Proxy-Authorization header field, the REGISTER should be resubmitted
+ to the registrar.
+
+ Since the registrar requires the user agent to authenticate
+ itself, it would be difficult for an attacker to forge REGISTER
+ requests for the user's address-of-record. Also note that since
+ the REGISTER is sent over a confidential TLS connection, attackers
+ will not be able to intercept the REGISTER to record credentials
+ for any possible replay attack.
+
+ Once the registration has been accepted by the registrar, the UA
+ SHOULD leave this TLS connection open provided that the registrar
+ also acts as the proxy server to which requests are sent for users in
+ this administrative domain. The existing TLS connection will be
+ reused to deliver incoming requests to the UA that has just completed
+ registration.
+
+ Because the UA has already authenticated the server on the other
+ side of the TLS connection, all requests that come over this
+ connection are known to have passed through the proxy server -
+ attackers cannot create spoofed requests that appear to have been
+ sent through that proxy server.
+
+26.3.2.2 Interdomain Requests
+
+ Now let's say that Alice's UA would like to initiate a session with a
+ user in a remote administrative domain, namely "bob@biloxi.com". We
+ will also say that the local administrative domain (atlanta.com) has
+ a local outbound proxy.
+
+ The proxy server that handles inbound requests for an administrative
+ domain MAY also act as a local outbound proxy; for simplicity's sake
+ we'll assume this to be the case for atlanta.com (otherwise the user
+ agent would initiate a new TLS connection to a separate server at
+ this point). Assuming that the client has completed the registration
+
+
+
+Rosenberg, et. al. Standards Track [Page 243]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ process described in the preceding section, it SHOULD reuse the TLS
+ connection to the local proxy server when it sends an INVITE request
+ to another user. The UA SHOULD reuse cached credentials in the
+ INVITE to avoid prompting the user unnecessarily.
+
+ When the local outbound proxy server has validated the credentials
+ presented by the UA in the INVITE, it SHOULD inspect the Request-URI
+ to determine how the message should be routed (see [4]). If the
+ "domainname" portion of the Request-URI had corresponded to the local
+ domain (atlanta.com) rather than biloxi.com, then the proxy server
+ would have consulted its location service to determine how best to
+ reach the requested user.
+
+ Had "alice@atlanta.com" been attempting to contact, say,
+ "alex@atlanta.com", the local proxy would have proxied to the
+ request to the TLS connection Alex had established with the
+ registrar when he registered. Since Alex would receive this
+ request over his authenticated channel, he would be assured that
+ Alice's request had been authorized by the proxy server of the
+ local administrative domain.
+
+ However, in this instance the Request-URI designates a remote domain.
+ The local outbound proxy server at atlanta.com SHOULD therefore
+ establish a TLS connection with the remote proxy server at
+ biloxi.com. Since both of the participants in this TLS connection
+ are servers that possess site certificates, mutual TLS authentication
+ SHOULD occur. Each side of the connection SHOULD verify and inspect
+ the certificate of the other, noting the domain name that appears in
+ the certificate for comparison with the header fields of SIP
+ messages. The atlanta.com proxy server, for example, SHOULD verify
+ at this stage that the certificate received from the remote side
+ corresponds with the biloxi.com domain. Once it has done so, and TLS
+ negotiation has completed, resulting in a secure channel between the
+ two proxies, the atlanta.com proxy can forward the INVITE request to
+ biloxi.com.
+
+ The proxy server at biloxi.com SHOULD inspect the certificate of the
+ proxy server at atlanta.com in turn and compare the domain asserted
+ by the certificate with the "domainname" portion of the From header
+ field in the INVITE request. The biloxi proxy MAY have a strict
+ security policy that requires it to reject requests that do not match
+ the administrative domain from which they have been proxied.
+
+ Such security policies could be instituted to prevent the SIP
+ equivalent of SMTP 'open relays' that are frequently exploited to
+ generate spam.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 244]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ This policy, however, only guarantees that the request came from the
+ domain it ascribes to itself; it does not allow biloxi.com to
+ ascertain how atlanta.com authenticated Alice. Only if biloxi.com
+ has some other way of knowing atlanta.com's authentication policies
+ could it possibly ascertain how Alice proved her identity.
+ biloxi.com might then institute an even stricter policy that forbids
+ requests that come from domains that are not known administratively
+ to share a common authentication policy with biloxi.com.
+
+ Once the INVITE has been approved by the biloxi proxy, the proxy
+ server SHOULD identify the existing TLS channel, if any, associated
+ with the user targeted by this request (in this case
+ "bob@biloxi.com"). The INVITE should be proxied through this channel
+ to Bob. Since the request is received over a TLS connection that had
+ previously been authenticated as the biloxi proxy, Bob knows that the
+ From header field was not tampered with and that atlanta.com has
+ validated Alice, although not necessarily whether or not to trust
+ Alice's identity.
+
+ Before they forward the request, both proxy servers SHOULD add a
+ Record-Route header field to the request so that all future requests
+ in this dialog will pass through the proxy servers. The proxy
+ servers can thereby continue to provide security services for the
+ lifetime of this dialog. If the proxy servers do not add themselves
+ to the Record-Route, future messages will pass directly end-to-end
+ between Alice and Bob without any security services (unless the two
+ parties agree on some independent end-to-end security such as
+ S/MIME). In this respect the SIP trapezoid model can provide a nice
+ structure where conventions of agreement between the site proxies can
+ provide a reasonably secure channel between Alice and Bob.
+
+ An attacker preying on this architecture would, for example, be
+ unable to forge a BYE request and insert it into the signaling
+ stream between Bob and Alice because the attacker has no way of
+ ascertaining the parameters of the session and also because the
+ integrity mechanism transitively protects the traffic between
+ Alice and Bob.
+
+26.3.2.3 Peer-to-Peer Requests
+
+ Alternatively, consider a UA asserting the identity
+ "carol@chicago.com" that has no local outbound proxy. When Carol
+ wishes to send an INVITE to "bob@biloxi.com", her UA SHOULD initiate
+ a TLS connection with the biloxi proxy directly (using the mechanism
+ described in [4] to determine how to best to reach the given
+ Request-URI). When her UA receives a certificate from the biloxi
+ proxy, it SHOULD be verified normally before she passes her INVITE
+ across the TLS connection. However, Carol has no means of proving
+
+
+
+Rosenberg, et. al. Standards Track [Page 245]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ her identity to the biloxi proxy, but she does have a CMS-detached
+ signature over a "message/sip" body in the INVITE. It is unlikely in
+ this instance that Carol would have any credentials in the biloxi.com
+ realm, since she has no formal association with biloxi.com. The
+ biloxi proxy MAY also have a strict policy that precludes it from
+ even bothering to challenge requests that do not have biloxi.com in
+ the "domainname" portion of the From header field - it treats these
+ users as unauthenticated.
+
+ The biloxi proxy has a policy for Bob that all non-authenticated
+ requests should be redirected to the appropriate contact address
+ registered against 'bob@biloxi.com', namely <sip:bob@192.0.2.4>.
+ Carol receives the redirection response over the TLS connection she
+ established with the biloxi proxy, so she trusts the veracity of the
+ contact address.
+
+ Carol SHOULD then establish a TCP connection with the designated
+ address and send a new INVITE with a Request-URI containing the
+ received contact address (recomputing the signature in the body as
+ the request is readied). Bob receives this INVITE on an insecure
+ interface, but his UA inspects and, in this instance, recognizes the
+ From header field of the request and subsequently matches a locally
+ cached certificate with the one presented in the signature of the
+ body of the INVITE. He replies in similar fashion, authenticating
+ himself to Carol, and a secure dialog begins.
+
+ Sometimes firewalls or NATs in an administrative domain could
+ preclude the establishment of a direct TCP connection to a UA. In
+ these cases, proxy servers could also potentially relay requests
+ to UAs in a way that has no trust implications (for example,
+ forgoing an existing TLS connection and forwarding the request
+ over cleartext TCP) as local policy dictates.
+
+26.3.2.4 DoS Protection
+
+ In order to minimize the risk of a denial-of-service attack against
+ architectures using these security solutions, implementers should
+ take note of the following guidelines.
+
+ When the host on which a SIP proxy server is operating is routable
+ from the public Internet, it SHOULD be deployed in an administrative
+ domain with defensive operational policies (blocking source-routed
+ traffic, preferably filtering ping traffic). Both TLS and IPSec can
+ also make use of bastion hosts at the edges of administrative domains
+ that participate in the security associations to aggregate secure
+ tunnels and sockets. These bastion hosts can also take the brunt of
+ denial-of-service attacks, ensuring that SIP hosts within the
+ administrative domain are not encumbered with superfluous messaging.
+
+
+
+Rosenberg, et. al. Standards Track [Page 246]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ No matter what security solutions are deployed, floods of messages
+ directed at proxy servers can lock up proxy server resources and
+ prevent desirable traffic from reaching its destination. There is a
+ computational expense associated with processing a SIP transaction at
+ a proxy server, and that expense is greater for stateful proxy
+ servers than it is for stateless proxy servers. Therefore, stateful
+ proxies are more susceptible to flooding than stateless proxy
+ servers.
+
+ UAs and proxy servers SHOULD challenge questionable requests with
+ only a single 401 (Unauthorized) or 407 (Proxy Authentication
+ Required), forgoing the normal response retransmission algorithm, and
+ thus behaving statelessly towards unauthenticated requests.
+
+ Retransmitting the 401 (Unauthorized) or 407 (Proxy Authentication
+ Required) status response amplifies the problem of an attacker
+ using a falsified header field value (such as Via) to direct
+ traffic to a third party.
+
+ In summary, the mutual authentication of proxy servers through
+ mechanisms such as TLS significantly reduces the potential for rogue
+ intermediaries to introduce falsified requests or responses that can
+ deny service. This commensurately makes it harder for attackers to
+ make innocent SIP nodes into agents of amplification.
+
+26.4 Limitations
+
+ Although these security mechanisms, when applied in a judicious
+ manner, can thwart many threats, there are limitations in the scope
+ of the mechanisms that must be understood by implementers and network
+ operators.
+
+26.4.1 HTTP Digest
+
+ One of the primary limitations of using HTTP Digest in SIP is that
+ the integrity mechanisms in Digest do not work very well for SIP.
+ Specifically, they offer protection of the Request-URI and the method
+ of a message, but not for any of the header fields that UAs would
+ most likely wish to secure.
+
+ The existing replay protection mechanisms described in RFC 2617 also
+ have some limitations for SIP. The next-nonce mechanism, for
+ example, does not support pipelined requests. The nonce-count
+ mechanism should be used for replay protection.
+
+ Another limitation of HTTP Digest is the scope of realms. Digest is
+ valuable when a user wants to authenticate themselves to a resource
+ with which they have a pre-existing association, like a service
+
+
+
+Rosenberg, et. al. Standards Track [Page 247]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ provider of which the user is a customer (which is quite a common
+ scenario and thus Digest provides an extremely useful function). By
+ way of contrast, the scope of TLS is interdomain or multirealm, since
+ certificates are often globally verifiable, so that the UA can
+ authenticate the server with no pre-existing association.
+
+26.4.2 S/MIME
+
+ The largest outstanding defect with the S/MIME mechanism is the lack
+ of a prevalent public key infrastructure for end users. If self-
+ signed certificates (or certificates that cannot be verified by one
+ of the participants in a dialog) are used, the SIP-based key exchange
+ mechanism described in Section 23.2 is susceptible to a man-in-the-
+ middle attack with which an attacker can potentially inspect and
+ modify S/MIME bodies. The attacker needs to intercept the first
+ exchange of keys between the two parties in a dialog, remove the
+ existing CMS-detached signatures from the request and response, and
+ insert a different CMS-detached signature containing a certificate
+ supplied by the attacker (but which seems to be a certificate for the
+ proper address-of-record). Each party will think they have exchanged
+ keys with the other, when in fact each has the public key of the
+ attacker.
+
+ It is important to note that the attacker can only leverage this
+ vulnerability on the first exchange of keys between two parties - on
+ subsequent occasions, the alteration of the key would be noticeable
+ to the UAs. It would also be difficult for the attacker to remain in
+ the path of all future dialogs between the two parties over time (as
+ potentially days, weeks, or years pass).
+
+ SSH is susceptible to the same man-in-the-middle attack on the first
+ exchange of keys; however, it is widely acknowledged that while SSH
+ is not perfect, it does improve the security of connections. The use
+ of key fingerprints could provide some assistance to SIP, just as it
+ does for SSH. For example, if two parties use SIP to establish a
+ voice communications session, each could read off the fingerprint of
+ the key they received from the other, which could be compared against
+ the original. It would certainly be more difficult for the man-in-
+ the-middle to emulate the voices of the participants than their
+ signaling (a practice that was used with the Clipper chip-based
+ secure telephone).
+
+ The S/MIME mechanism allows UAs to send encrypted requests without
+ preamble if they possess a certificate for the destination address-
+ of-record on their keyring. However, it is possible that any
+ particular device registered for an address-of-record will not hold
+ the certificate that has been previously employed by the device's
+ current user, and that it will therefore be unable to process an
+
+
+
+Rosenberg, et. al. Standards Track [Page 248]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ encrypted request properly, which could lead to some avoidable error
+ signaling. This is especially likely when an encrypted request is
+ forked.
+
+ The keys associated with S/MIME are most useful when associated with
+ a particular user (an address-of-record) rather than a device (a UA).
+ When users move between devices, it may be difficult to transport
+ private keys securely between UAs; how such keys might be acquired by
+ a device is outside the scope of this document.
+
+ Another, more prosaic difficulty with the S/MIME mechanism is that it
+ can result in very large messages, especially when the SIP tunneling
+ mechanism described in Section 23.4 is used. For that reason, it is
+ RECOMMENDED that TCP should be used as a transport protocol when
+ S/MIME tunneling is employed.
+
+26.4.3 TLS
+
+ The most commonly voiced concern about TLS is that it cannot run over
+ UDP; TLS requires a connection-oriented underlying transport
+ protocol, which for the purposes of this document means TCP.
+
+ It may also be arduous for a local outbound proxy server and/or
+ registrar to maintain many simultaneous long-lived TLS connections
+ with numerous UAs. This introduces some valid scalability concerns,
+ especially for intensive ciphersuites. Maintaining redundancy of
+ long-lived TLS connections, especially when a UA is solely
+ responsible for their establishment, could also be cumbersome.
+
+ TLS only allows SIP entities to authenticate servers to which they
+ are adjacent; TLS offers strictly hop-by-hop security. Neither TLS,
+ nor any other mechanism specified in this document, allows clients to
+ authenticate proxy servers to whom they cannot form a direct TCP
+ connection.
+
+26.4.4 SIPS URIs
+
+ Actually using TLS on every segment of a request path entails that
+ the terminating UAS must be reachable over TLS (perhaps registering
+ with a SIPS URI as a contact address). This is the preferred use of
+ SIPS. Many valid architectures, however, use TLS to secure part of
+ the request path, but rely on some other mechanism for the final hop
+ to a UAS, for example. Thus SIPS cannot guarantee that TLS usage
+ will be truly end-to-end. Note that since many UAs will not accept
+ incoming TLS connections, even those UAs that do support TLS may be
+ required to maintain persistent TLS connections as described in the
+ TLS limitations section above in order to receive requests over TLS
+ as a UAS.
+
+
+
+Rosenberg, et. al. Standards Track [Page 249]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Location services are not required to provide a SIPS binding for a
+ SIPS Request-URI. Although location services are commonly populated
+ by user registrations (as described in Section 10.2.1), various other
+ protocols and interfaces could conceivably supply contact addresses
+ for an AOR, and these tools are free to map SIPS URIs to SIP URIs as
+ appropriate. When queried for bindings, a location service returns
+ its contact addresses without regard for whether it received a
+ request with a SIPS Request-URI. If a redirect server is accessing
+ the location service, it is up to the entity that processes the
+ Contact header field of a redirection to determine the propriety of
+ the contact addresses.
+
+ Ensuring that TLS will be used for all of the request segments up to
+ the target domain is somewhat complex. It is possible that
+ cryptographically authenticated proxy servers along the way that are
+ non-compliant or compromised may choose to disregard the forwarding
+ rules associated with SIPS (and the general forwarding rules in
+ Section 16.6). Such malicious intermediaries could, for example,
+ retarget a request from a SIPS URI to a SIP URI in an attempt to
+ downgrade security.
+
+ Alternatively, an intermediary might legitimately retarget a request
+ from a SIP to a SIPS URI. Recipients of a request whose Request-URI
+ uses the SIPS URI scheme thus cannot assume on the basis of the
+ Request-URI alone that SIPS was used for the entire request path
+ (from the client onwards).
+
+ To address these concerns, it is RECOMMENDED that recipients of a
+ request whose Request-URI contains a SIP or SIPS URI inspect the To
+ header field value to see if it contains a SIPS URI (though note that
+ it does not constitute a breach of security if this URI has the same
+ scheme but is not equivalent to the URI in the To header field).
+ Although clients may choose to populate the Request-URI and To header
+ field of a request differently, when SIPS is used this disparity
+ could be interpreted as a possible security violation, and the
+ request could consequently be rejected by its recipient. Recipients
+ MAY also inspect the Via header chain in order to double-check
+ whether or not TLS was used for the entire request path until the
+ local administrative domain was reached. S/MIME may also be used by
+ the originating UAC to help ensure that the original form of the To
+ header field is carried end-to-end.
+
+ If the UAS has reason to believe that the scheme of the Request-URI
+ has been improperly modified in transit, the UA SHOULD notify its
+ user of a potential security breach.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 250]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ As a further measure to prevent downgrade attacks, entities that
+ accept only SIPS requests MAY also refuse connections on insecure
+ ports.
+
+ End users will undoubtedly discern the difference between SIPS and
+ SIP URIs, and they may manually edit them in response to stimuli.
+ This can either benefit or degrade security. For example, if an
+ attacker corrupts a DNS cache, inserting a fake record set that
+ effectively removes all SIPS records for a proxy server, then any
+ SIPS requests that traverse this proxy server may fail. When a user,
+ however, sees that repeated calls to a SIPS AOR are failing, they
+ could on some devices manually convert the scheme from SIPS to SIP
+ and retry. Of course, there are some safeguards against this (if the
+ destination UA is truly paranoid it could refuse all non-SIPS
+ requests), but it is a limitation worth noting. On the bright side,
+ users might also divine that 'SIPS' would be valid even when they are
+ presented only with a SIP URI.
+
+26.5 Privacy
+
+ SIP messages frequently contain sensitive information about their
+ senders - not just what they have to say, but with whom they
+ communicate, when they communicate and for how long, and from where
+ they participate in sessions. Many applications and their users
+ require that this sort of private information be hidden from any
+ parties that do not need to know it.
+
+ Note that there are also less direct ways in which private
+ information can be divulged. If a user or service chooses to be
+ reachable at an address that is guessable from the person's name and
+ organizational affiliation (which describes most addresses-of-
+ record), the traditional method of ensuring privacy by having an
+ unlisted "phone number" is compromised. A user location service can
+ infringe on the privacy of the recipient of a session invitation by
+ divulging their specific whereabouts to the caller; an implementation
+ consequently SHOULD be able to restrict, on a per-user basis, what
+ kind of location and availability information is given out to certain
+ classes of callers. This is a whole class of problem that is
+ expected to be studied further in ongoing SIP work.
+
+ In some cases, users may want to conceal personal information in
+ header fields that convey identity. This can apply not only to the
+ From and related headers representing the originator of the request,
+ but also the To - it may not be appropriate to convey to the final
+ destination a speed-dialing nickname, or an unexpanded identifier for
+ a group of targets, either of which would be removed from the
+ Request-URI as the request is routed, but not changed in the To
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 251]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ header field if the two were initially identical. Thus it MAY be
+ desirable for privacy reasons to create a To header field that
+ differs from the Request-URI.
+
+27 IANA Considerations
+
+ All method names, header field names, status codes, and option tags
+ used in SIP applications are registered with IANA through
+ instructions in an IANA Considerations section in an RFC.
+
+ The specification instructs the IANA to create four new sub-
+ registries under http://www.iana.org/assignments/sip-parameters:
+ Option Tags, Warning Codes (warn-codes), Methods and Response Codes,
+ added to the sub-registry of Header Fields that is already present
+ there.
+
+27.1 Option Tags
+
+ This specification establishes the Option Tags sub-registry under
+ http://www.iana.org/assignments/sip-parameters.
+
+ Option tags are used in header fields such as Require, Supported,
+ Proxy-Require, and Unsupported in support of SIP compatibility
+ mechanisms for extensions (Section 19.2). The option tag itself is a
+ string that is associated with a particular SIP option (that is, an
+ extension). It identifies the option to SIP endpoints.
+
+ Option tags are registered by the IANA when they are published in
+ standards track RFCs. The IANA Considerations section of the RFC
+ must include the following information, which appears in the IANA
+ registry along with the RFC number of the publication.
+
+ o Name of the option tag. The name MAY be of any length, but
+ SHOULD be no more than twenty characters long. The name MUST
+ consist of alphanum (Section 25) characters only.
+
+ o Descriptive text that describes the extension.
+
+27.2 Warn-Codes
+
+ This specification establishes the Warn-codes sub-registry under
+ http://www.iana.org/assignments/sip-parameters and initiates its
+ population with the warn-codes listed in Section 20.43. Additional
+ warn-codes are registered by RFC publication.
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 252]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ The descriptive text for the table of warn-codes is:
+
+ Warning codes provide information supplemental to the status code in
+ SIP response messages when the failure of the transaction results
+ from a Session Description Protocol (SDP) (RFC 2327 [1]) problem.
+
+ The "warn-code" consists of three digits. A first digit of "3"
+ indicates warnings specific to SIP. Until a future specification
+ describes uses of warn-codes other than 3xx, only 3xx warn-codes may
+ be registered.
+
+ Warnings 300 through 329 are reserved for indicating problems with
+ keywords in the session description, 330 through 339 are warnings
+ related to basic network services requested in the session
+ description, 370 through 379 are warnings related to quantitative QoS
+ parameters requested in the session description, and 390 through 399
+ are miscellaneous warnings that do not fall into one of the above
+ categories.
+
+27.3 Header Field Names
+
+ This obsoletes the IANA instructions about the header sub-registry
+ under http://www.iana.org/assignments/sip-parameters.
+
+ The following information needs to be provided in an RFC publication
+ in order to register a new header field name:
+
+ o The RFC number in which the header is registered;
+
+ o the name of the header field being registered;
+
+ o a compact form version for that header field, if one is
+ defined;
+
+ Some common and widely used header fields MAY be assigned one-letter
+ compact forms (Section 7.3.3). Compact forms can only be assigned
+ after SIP working group review, followed by RFC publication.
+
+27.4 Method and Response Codes
+
+ This specification establishes the Method and Response-Code sub-
+ registries under http://www.iana.org/assignments/sip-parameters and
+ initiates their population as follows. The initial Methods table is:
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 253]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ INVITE [RFC3261]
+ ACK [RFC3261]
+ BYE [RFC3261]
+ CANCEL [RFC3261]
+ REGISTER [RFC3261]
+ OPTIONS [RFC3261]
+ INFO [RFC2976]
+
+ The response code table is initially populated from Section 21, the
+ portions labeled Informational, Success, Redirection, Client-Error,
+ Server-Error, and Global-Failure. The table has the following
+ format:
+
+ Type (e.g., Informational)
+ Number Default Reason Phrase [RFC3261]
+
+ The following information needs to be provided in an RFC publication
+ in order to register a new response code or method:
+
+ o The RFC number in which the method or response code is
+ registered;
+
+ o the number of the response code or name of the method being
+ registered;
+
+ o the default reason phrase for that response code, if
+ applicable;
+
+27.5 The "message/sip" MIME type.
+
+ This document registers the "message/sip" MIME media type in order to
+ allow SIP messages to be tunneled as bodies within SIP, primarily for
+ end-to-end security purposes. This media type is defined by the
+ following information:
+
+ Media type name: message
+ Media subtype name: sip
+ Required parameters: none
+
+ Optional parameters: version
+ version: The SIP-Version number of the enclosed message (e.g.,
+ "2.0"). If not present, the version defaults to "2.0".
+ Encoding scheme: SIP messages consist of an 8-bit header
+ optionally followed by a binary MIME data object. As such, SIP
+ messages must be treated as binary. Under normal circumstances
+ SIP messages are transported over binary-capable transports, no
+ special encodings are needed.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 254]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Security considerations: see below
+ Motivation and examples of this usage as a security mechanism
+ in concert with S/MIME are given in 23.4.
+
+27.6 New Content-Disposition Parameter Registrations
+
+ This document also registers four new Content-Disposition header
+ "disposition-types": alert, icon, session and render. The authors
+ request that these values be recorded in the IANA registry for
+ Content-Dispositions.
+
+ Descriptions of these "disposition-types", including motivation and
+ examples, are given in Section 20.11.
+
+ Short descriptions suitable for the IANA registry are:
+
+ alert the body is a custom ring tone to alert the user
+ icon the body is displayed as an icon to the user
+ render the body should be displayed to the user
+ session the body describes a communications session, for
+ example, as RFC 2327 SDP body
+
+28 Changes From RFC 2543
+
+ This RFC revises RFC 2543. It is mostly backwards compatible with
+ RFC 2543. The changes described here fix many errors discovered in
+ RFC 2543 and provide information on scenarios not detailed in RFC
+ 2543. The protocol has been presented in a more cleanly layered
+ model here.
+
+ We break the differences into functional behavior that is a
+ substantial change from RFC 2543, which has impact on
+ interoperability or correct operation in some cases, and functional
+ behavior that is different from RFC 2543 but not a potential source
+ of interoperability problems. There have been countless
+ clarifications as well, which are not documented here.
+
+28.1 Major Functional Changes
+
+ o When a UAC wishes to terminate a call before it has been answered,
+ it sends CANCEL. If the original INVITE still returns a 2xx, the
+ UAC then sends BYE. BYE can only be sent on an existing call leg
+ (now called a dialog in this RFC), whereas it could be sent at any
+ time in RFC 2543.
+
+ o The SIP BNF was converted to be RFC 2234 compliant.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 255]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o SIP URL BNF was made more general, allowing a greater set of
+ characters in the user part. Furthermore, comparison rules were
+ simplified to be primarily case-insensitive, and detailed handling
+ of comparison in the presence of parameters was described. The
+ most substantial change is that a URI with a parameter with the
+ default value does not match a URI without that parameter.
+
+ o Removed Via hiding. It had serious trust issues, since it relied
+ on the next hop to perform the obfuscation process. Instead, Via
+ hiding can be done as a local implementation choice in stateful
+ proxies, and thus is no longer documented.
+
+ o In RFC 2543, CANCEL and INVITE transactions were intermingled.
+ They are separated now. When a user sends an INVITE and then a
+ CANCEL, the INVITE transaction still terminates normally. A UAS
+ needs to respond to the original INVITE request with a 487
+ response.
+
+ o Similarly, CANCEL and BYE transactions were intermingled; RFC 2543
+ allowed the UAS not to send a response to INVITE when a BYE was
+ received. That is disallowed here. The original INVITE needs a
+ response.
+
+ o In RFC 2543, UAs needed to support only UDP. In this RFC, UAs
+ need to support both UDP and TCP.
+
+ o In RFC 2543, a forking proxy only passed up one challenge from
+ downstream elements in the event of multiple challenges. In this
+ RFC, proxies are supposed to collect all challenges and place them
+ into the forwarded response.
+
+ o In Digest credentials, the URI needs to be quoted; this is unclear
+ from RFC 2617 and RFC 2069 which are both inconsistent on it.
+
+ o SDP processing has been split off into a separate specification
+ [13], and more fully specified as a formal offer/answer exchange
+ process that is effectively tunneled through SIP. SDP is allowed
+ in INVITE/200 or 200/ACK for baseline SIP implementations; RFC
+ 2543 alluded to the ability to use it in INVITE, 200, and ACK in a
+ single transaction, but this was not well specified. More complex
+ SDP usages are allowed in extensions.
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 256]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o Added full support for IPv6 in URIs and in the Via header field.
+ Support for IPv6 in Via has required that its header field
+ parameters allow the square bracket and colon characters. These
+ characters were previously not permitted. In theory, this could
+ cause interop problems with older implementations. However, we
+ have observed that most implementations accept any non-control
+ ASCII character in these parameters.
+
+ o DNS SRV procedure is now documented in a separate specification
+ [4]. This procedure uses both SRV and NAPTR resource records and
+ no longer combines data from across SRV records as described in
+ RFC 2543.
+
+ o Loop detection has been made optional, supplanted by a mandatory
+ usage of Max-Forwards. The loop detection procedure in RFC 2543
+ had a serious bug which would report "spirals" as an error
+ condition when it was not. The optional loop detection procedure
+ is more fully and correctly specified here.
+
+ o Usage of tags is now mandatory (they were optional in RFC 2543),
+ as they are now the fundamental building blocks of dialog
+ identification.
+
+ o Added the Supported header field, allowing for clients to indicate
+ what extensions are supported to a server, which can apply those
+ extensions to the response, and indicate their usage with a
+ Require in the response.
+
+ o Extension parameters were missing from the BNF for several header
+ fields, and they have been added.
+
+ o Handling of Route and Record-Route construction was very
+ underspecified in RFC 2543, and also not the right approach. It
+ has been substantially reworked in this specification (and made
+ vastly simpler), and this is arguably the largest change.
+ Backwards compatibility is still provided for deployments that do
+ not use "pre-loaded routes", where the initial request has a set
+ of Route header field values obtained in some way outside of
+ Record-Route. In those situations, the new mechanism is not
+ interoperable.
+
+ o In RFC 2543, lines in a message could be terminated with CR, LF,
+ or CRLF. This specification only allows CRLF.
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 257]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o Usage of Route in CANCEL and ACK was not well defined in RFC 2543.
+ It is now well specified; if a request had a Route header field,
+ its CANCEL or ACK for a non-2xx response to the request need to
+ carry the same Route header field values. ACKs for 2xx responses
+ use the Route values learned from the Record-Route of the 2xx
+ responses.
+
+ o RFC 2543 allowed multiple requests in a single UDP packet. This
+ usage has been removed.
+
+ o Usage of absolute time in the Expires header field and parameter
+ has been removed. It caused interoperability problems in elements
+ that were not time synchronized, a common occurrence. Relative
+ times are used instead.
+
+ o The branch parameter of the Via header field value is now
+ mandatory for all elements to use. It now plays the role of a
+ unique transaction identifier. This avoids the complex and bug-
+ laden transaction identification rules from RFC 2543. A magic
+ cookie is used in the parameter value to determine if the previous
+ hop has made the parameter globally unique, and comparison falls
+ back to the old rules when it is not present. Thus,
+ interoperability is assured.
+
+ o In RFC 2543, closure of a TCP connection was made equivalent to a
+ CANCEL. This was nearly impossible to implement (and wrong) for
+ TCP connections between proxies. This has been eliminated, so
+ that there is no coupling between TCP connection state and SIP
+ processing.
+
+ o RFC 2543 was silent on whether a UA could initiate a new
+ transaction to a peer while another was in progress. That is now
+ specified here. It is allowed for non-INVITE requests, disallowed
+ for INVITE.
+
+ o PGP was removed. It was not sufficiently specified, and not
+ compatible with the more complete PGP MIME. It was replaced with
+ S/MIME.
+
+ o Added the "sips" URI scheme for end-to-end TLS. This scheme is
+ not backwards compatible with RFC 2543. Existing elements that
+ receive a request with a SIPS URI scheme in the Request-URI will
+ likely reject the request. This is actually a feature; it ensures
+ that a call to a SIPS URI is only delivered if all path hops can
+ be secured.
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 258]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o Additional security features were added with TLS, and these are
+ described in a much larger and complete security considerations
+ section.
+
+ o In RFC 2543, a proxy was not required to forward provisional
+ responses from 101 to 199 upstream. This was changed to MUST.
+ This is important, since many subsequent features depend on
+ delivery of all provisional responses from 101 to 199.
+
+ o Little was said about the 503 response code in RFC 2543. It has
+ since found substantial use in indicating failure or overload
+ conditions in proxies. This requires somewhat special treatment.
+ Specifically, receipt of a 503 should trigger an attempt to
+ contact the next element in the result of a DNS SRV lookup. Also,
+ 503 response is only forwarded upstream by a proxy under certain
+ conditions.
+
+ o RFC 2543 defined, but did no sufficiently specify, a mechanism for
+ UA authentication of a server. That has been removed. Instead,
+ the mutual authentication procedures of RFC 2617 are allowed.
+
+ o A UA cannot send a BYE for a call until it has received an ACK for
+ the initial INVITE. This was allowed in RFC 2543 but leads to a
+ potential race condition.
+
+ o A UA or proxy cannot send CANCEL for a transaction until it gets a
+ provisional response for the request. This was allowed in RFC
+ 2543 but leads to potential race conditions.
+
+ o The action parameter in registrations has been deprecated. It was
+ insufficient for any useful services, and caused conflicts when
+ application processing was applied in proxies.
+
+ o RFC 2543 had a number of special cases for multicast. For
+ example, certain responses were suppressed, timers were adjusted,
+ and so on. Multicast now plays a more limited role, and the
+ protocol operation is unaffected by usage of multicast as opposed
+ to unicast. The limitations as a result of that are documented.
+
+ o Basic authentication has been removed entirely and its usage
+ forbidden.
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 259]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ o Proxies no longer forward a 6xx immediately on receiving it.
+ Instead, they CANCEL pending branches immediately. This avoids a
+ potential race condition that would result in a UAC getting a 6xx
+ followed by a 2xx. In all cases except this race condition, the
+ result will be the same - the 6xx is forwarded upstream.
+
+ o RFC 2543 did not address the problem of request merging. This
+ occurs when a request forks at a proxy and later rejoins at an
+ element. Handling of merging is done only at a UA, and procedures
+ are defined for rejecting all but the first request.
+
+28.2 Minor Functional Changes
+
+ o Added the Alert-Info, Error-Info, and Call-Info header fields for
+ optional content presentation to users.
+
+ o Added the Content-Language, Content-Disposition and MIME-Version
+ header fields.
+
+ o Added a "glare handling" mechanism to deal with the case where
+ both parties send each other a re-INVITE simultaneously. It uses
+ the new 491 (Request Pending) error code.
+
+ o Added the In-Reply-To and Reply-To header fields for supporting
+ the return of missed calls or messages at a later time.
+
+ o Added TLS and SCTP as valid SIP transports.
+
+ o There were a variety of mechanisms described for handling failures
+ at any time during a call; those are now generally unified. BYE
+ is sent to terminate.
+
+ o RFC 2543 mandated retransmission of INVITE responses over TCP, but
+ noted it was really only needed for 2xx. That was an artifact of
+ insufficient protocol layering. With a more coherent transaction
+ layer defined here, that is no longer needed. Only 2xx responses
+ to INVITEs are retransmitted over TCP.
+
+ o Client and server transaction machines are now driven based on
+ timeouts rather than retransmit counts. This allows the state
+ machines to be properly specified for TCP and UDP.
+
+ o The Date header field is used in REGISTER responses to provide a
+ simple means for auto-configuration of dates in user agents.
+
+ o Allowed a registrar to reject registrations with expirations that
+ are too short in duration. Defined the 423 response code and the
+ Min-Expires for this purpose.
+
+
+
+Rosenberg, et. al. Standards Track [Page 260]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+29 Normative References
+
+ [1] Handley, M. and V. Jacobson, "SDP: Session Description
+ Protocol", RFC 2327, April 1998.
+
+ [2] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [3] Resnick, P., "Internet Message Format", RFC 2822, April 2001.
+
+ [4] Rosenberg, J. and H. Schulzrinne, "SIP: Locating SIP Servers",
+ RFC 3263, June 2002.
+
+ [5] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource
+ Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
+
+ [6] Chown, P., "Advanced Encryption Standard (AES) Ciphersuites for
+ Transport Layer Security (TLS)", RFC 3268, June 2002.
+
+ [7] Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC
+ 2279, January 1998.
+
+ [8] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L.,
+ Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", RFC 2616, June 1999.
+
+ [9] Vaha-Sipila, A., "URLs for Telephone Calls", RFC 2806, April
+ 2000.
+
+ [10] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [11] Freed, F. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046, November
+ 1996.
+
+ [12] Eastlake, D., Crocker, S. and J. Schiller, "Randomness
+ Recommendations for Security", RFC 1750, December 1994.
+
+ [13] Rosenberg, J. and H. Schulzrinne, "An Offer/Answer Model with
+ SDP", RFC 3264, June 2002.
+
+ [14] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August
+ 1980.
+
+ [15] Postel, J., "DoD Standard Transmission Control Protocol", RFC
+ 761, January 1980.
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 261]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ [16] Stewart, R., Xie, Q., Morneault, K., Sharp, C., Schwarzbauer,
+ H., Taylor, T., Rytina, I., Kalla, M., Zhang, L. and V. Paxson,
+ "Stream Control Transmission Protocol", RFC 2960, October 2000.
+
+ [17] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S.,
+ Leach, P., Luotonen, A. and L. Stewart, "HTTP authentication:
+ Basic and Digest Access Authentication", RFC 2617, June 1999.
+
+ [18] Troost, R., Dorner, S. and K. Moore, "Communicating Presentation
+ Information in Internet Messages: The Content-Disposition Header
+ Field", RFC 2183, August 1997.
+
+ [19] Zimmerer, E., Peterson, J., Vemuri, A., Ong, L., Audet, F.,
+ Watson, M. and M. Zonoun, "MIME media types for ISUP and QSIG
+ Objects", RFC 3204, December 2001.
+
+ [20] Braden, R., "Requirements for Internet Hosts - Application and
+ Support", STD 3, RFC 1123, October 1989.
+
+ [21] Alvestrand, H., "IETF Policy on Character Sets and Languages",
+ BCP 18, RFC 2277, January 1998.
+
+ [22] Galvin, J., Murphy, S., Crocker, S. and N. Freed, "Security
+ Multiparts for MIME: Multipart/Signed and Multipart/Encrypted",
+ RFC 1847, October 1995.
+
+ [23] Housley, R., "Cryptographic Message Syntax", RFC 2630, June
+ 1999.
+
+ [24] Ramsdell B., "S/MIME Version 3 Message Specification", RFC 2633,
+ June 1999.
+
+ [25] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC
+ 2246, January 1999.
+
+ [26] Kent, S. and R. Atkinson, "Security Architecture for the
+ Internet Protocol", RFC 2401, November 1998.
+
+30 Informative References
+
+ [27] R. Pandya, "Emerging mobile and personal communication systems,"
+ IEEE Communications Magazine, Vol. 33, pp. 44--52, June 1995.
+
+ [28] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson,
+ "RTP: A Transport Protocol for Real-Time Applications", RFC
+ 1889, January 1996.
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 262]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ [29] Schulzrinne, H., Rao, R. and R. Lanphier, "Real Time Streaming
+ Protocol (RTSP)", RFC 2326, April 1998.
+
+ [30] Cuervo, F., Greene, N., Rayhan, A., Huitema, C., Rosen, B. and
+ J. Segers, "Megaco Protocol Version 1.0", RFC 3015, November
+ 2000.
+
+ [31] Handley, M., Schulzrinne, H., Schooler, E. and J. Rosenberg,
+ "SIP: Session Initiation Protocol", RFC 2543, March 1999.
+
+ [32] Hoffman, P., Masinter, L. and J. Zawinski, "The mailto URL
+ scheme", RFC 2368, July 1998.
+
+ [33] E. M. Schooler, "A multicast user directory service for
+ synchronous rendezvous," Master's Thesis CS-TR-96-18, Department
+ of Computer Science, California Institute of Technology,
+ Pasadena, California, Aug. 1996.
+
+ [34] Donovan, S., "The SIP INFO Method", RFC 2976, October 2000.
+
+ [35] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April
+ 1992.
+
+ [36] Dawson, F. and T. Howes, "vCard MIME Directory Profile", RFC
+ 2426, September 1998.
+
+ [37] Good, G., "The LDAP Data Interchange Format (LDIF) - Technical
+ Specification", RFC 2849, June 2000.
+
+ [38] Palme, J., "Common Internet Message Headers", RFC 2076,
+ February 1997.
+
+ [39] Franks, J., Hallam-Baker, P., Hostetler, J., Leach, P.,
+ Luotonen, A., Sink, E. and L. Stewart, "An Extension to HTTP:
+ Digest Access Authentication", RFC 2069, January 1997.
+
+ [40] Johnston, A., Donovan, S., Sparks, R., Cunningham, C., Willis,
+ D., Rosenberg, J., Summers, K. and H. Schulzrinne, "SIP Call
+ Flow Examples", Work in Progress.
+
+ [41] E. M. Schooler, "Case study: multimedia conference control in a
+ packet-switched teleconferencing system," Journal of
+ Internetworking: Research and Experience, Vol. 4, pp. 99--120,
+ June 1993. ISI reprint series ISI/RS-93-359.
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 263]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ [42] H. Schulzrinne, "Personal mobility for multimedia services in
+ the Internet," in European Workshop on Interactive Distributed
+ Multimedia Systems and Services (IDMS), (Berlin, Germany), Mar.
+ 1996.
+
+ [43] Floyd, S., "Congestion Control Principles", RFC 2914, September
+ 2000.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 264]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+A Table of Timer Values
+
+ Table 4 summarizes the meaning and defaults of the various timers
+ used by this specification.
+
+Timer Value Section Meaning
+----------------------------------------------------------------------
+T1 500ms default Section 17.1.1.1 RTT Estimate
+T2 4s Section 17.1.2.2 The maximum retransmit
+ interval for non-INVITE
+ requests and INVITE
+ responses
+T4 5s Section 17.1.2.2 Maximum duration a
+ message will
+ remain in the network
+Timer A initially T1 Section 17.1.1.2 INVITE request retransmit
+ interval, for UDP only
+Timer B 64*T1 Section 17.1.1.2 INVITE transaction
+ timeout timer
+Timer C > 3min Section 16.6 proxy INVITE transaction
+ bullet 11 timeout
+Timer D > 32s for UDP Section 17.1.1.2 Wait time for response
+ 0s for TCP/SCTP retransmits
+Timer E initially T1 Section 17.1.2.2 non-INVITE request
+ retransmit interval,
+ UDP only
+Timer F 64*T1 Section 17.1.2.2 non-INVITE transaction
+ timeout timer
+Timer G initially T1 Section 17.2.1 INVITE response
+ retransmit interval
+Timer H 64*T1 Section 17.2.1 Wait time for
+ ACK receipt
+Timer I T4 for UDP Section 17.2.1 Wait time for
+ 0s for TCP/SCTP ACK retransmits
+Timer J 64*T1 for UDP Section 17.2.2 Wait time for
+ 0s for TCP/SCTP non-INVITE request
+ retransmits
+Timer K T4 for UDP Section 17.1.2.2 Wait time for
+ 0s for TCP/SCTP response retransmits
+
+ Table 4: Summary of timers
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 265]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Acknowledgments
+
+ We wish to thank the members of the IETF MMUSIC and SIP WGs for their
+ comments and suggestions. Detailed comments were provided by Ofir
+ Arkin, Brian Bidulock, Jim Buller, Neil Deason, Dave Devanathan,
+ Keith Drage, Bill Fenner, Cedric Fluckiger, Yaron Goland, John
+ Hearty, Bernie Hoeneisen, Jo Hornsby, Phil Hoffer, Christian Huitema,
+ Hisham Khartabil, Jean Jervis, Gadi Karmi, Peter Kjellerstedt, Anders
+ Kristensen, Jonathan Lennox, Gethin Liddell, Allison Mankin, William
+ Marshall, Rohan Mahy, Keith Moore, Vern Paxson, Bob Penfield, Moshe
+ J. Sambol, Chip Sharp, Igor Slepchin, Eric Tremblay, and Rick
+ Workman.
+
+ Brian Rosen provided the compiled BNF.
+
+ Jean Mahoney provided technical writing assistance.
+
+ This work is based, inter alia, on [41,42].
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 266]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Authors' Addresses
+
+ Authors addresses are listed alphabetically for the editors, the
+ writers, and then the original authors of RFC 2543. All listed
+ authors actively contributed large amounts of text to this document.
+
+ Jonathan Rosenberg
+ dynamicsoft
+ 72 Eagle Rock Ave
+ East Hanover, NJ 07936
+ USA
+
+ EMail: jdrosen@dynamicsoft.com
+
+
+ Henning Schulzrinne
+ Dept. of Computer Science
+ Columbia University
+ 1214 Amsterdam Avenue
+ New York, NY 10027
+ USA
+
+ EMail: schulzrinne@cs.columbia.edu
+
+
+ Gonzalo Camarillo
+ Ericsson
+ Advanced Signalling Research Lab.
+ FIN-02420 Jorvas
+ Finland
+
+ EMail: Gonzalo.Camarillo@ericsson.com
+
+
+ Alan Johnston
+ WorldCom
+ 100 South 4th Street
+ St. Louis, MO 63102
+ USA
+
+ EMail: alan.johnston@wcom.com
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 267]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+ Jon Peterson
+ NeuStar, Inc
+ 1800 Sutter Street, Suite 570
+ Concord, CA 94520
+ USA
+
+ EMail: jon.peterson@neustar.com
+
+
+ Robert Sparks
+ dynamicsoft, Inc.
+ 5100 Tennyson Parkway
+ Suite 1200
+ Plano, Texas 75024
+ USA
+
+ EMail: rsparks@dynamicsoft.com
+
+
+ Mark Handley
+ International Computer Science Institute
+ 1947 Center St, Suite 600
+ Berkeley, CA 94704
+ USA
+
+ EMail: mjh@icir.org
+
+
+ Eve Schooler
+ AT&T Labs-Research
+ 75 Willow Road
+ Menlo Park, CA 94025
+ USA
+
+ EMail: schooler@research.att.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 268]
+
+RFC 3261 SIP: Session Initiation Protocol June 2002
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rosenberg, et. al. Standards Track [Page 269]
+
diff --git a/tests/auto/corelib/io/qtextstream/shift-jis.txt b/tests/auto/corelib/io/qtextstream/shift-jis.txt new file mode 100644 index 0000000000..51f161ab1a --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/shift-jis.txt @@ -0,0 +1,764 @@ +Shift-JISeLXgð³µµ€ +ÅßÌXVð +2005-03-26: uÅÉvAXMLú{êvt@Cæ2ÅÉîëAá±ÇLB +2005-03-09: uÅÉvA¶Íðá±C³B +2003-06-24: Shift-JISÌ¿ðÜÞt@CŒ/pXŒ +2003-05-31: uÅÉvAuVtgJISvÈÇÌ\LÉ¢ÄB +2003-05-24: CP932d¡è`¶ÌÏ· +2002-08-30: Perl 5.8.0 É¢ÄB +2002-01-17: ·¢¶ñÉηé³K\»õ +2001-12-15: ShiftJIS::Collate ª overrideCJK p[^ðp~µœ±Æɺ€ ú{ê¶ñðÀÑÖŠéÌ«·ŠB +ÅÉ + 調ÈG[ +G[âÔá¢ðh®Îô +¶ñeÌìèû +³K\»Æ}b` +O[o}b` +At@xbgÌå¶Æ¬¶ +·¢¶ñÉηé³K\»õ +OÌÏ· +CP932d¡è`¶ÌÏ· +¶ðŠé +¶PÊɪ·é +¢ë¢ëȪ +ÁèÌ·³ÅØè»ëŠé +ú{ê¶ñðÀÑÖŠé +Shift-JISÌ¿ðÜÞt@CŒ/pXŒ +ÅÉ +ú{ê̶R[hÉ͢©Ìà̪gíêĢܷB éöxêÊIÈàÌÈçAÇêðgÁÄàæ¢Åµå€iÇ̶R[hÅ»³êÄ¢é©Ìîñªží곊µÈ¯êÎjB +áŠÎAú{êÅWindowsÅÍA ÅàDOSÅàShift-JISªgíêĢܷB±€¢€êAÌrÅíŽíŽEUC-JPâUTF-8ÉÏ··éƵœçÊ|Å·BfobOÌÆ«Au±ÌiKÅͱÌÏÉÍœªüÁÄ¢éÌ©vo͵Ä_·éÌÍæsíêÜ·ªA±ÌÆ«EUC-JPƵÄûßçêÄ¢œçAìÆÍèÔÇéŵå€BüÍàoÍàShift-JISÅs€ÂàèÈçAÌSÌÅShift-JISÌÜܵŠœç«ÁÆÖŵå€B +F "VtgJIS", "Shift_JIS", "Shift-JIS" ÈÇÌ\LÌá¢É¢ÄÍæí©ÁĢܹñB¡ÌƱ목ÁÄ¢é±ÆÍF +JIS X 0208:1997Ì®1iVtg»\»jÉÍAuQlvƵÄu±Ì»\»ÍÊígVtgJISR[hhÆÄÎêÄ¢évÌLqª èÜ·B +IANA Ì CHARACTER SETS ÉÍAShift_JIS Æ Windows-31J ƪÊÉo^³êĢܷBÜœAShift_JISÉ¢ÄAuCCSi»¶WjÍJIS X0201:1997ÆJIS X0208:1997Å èA®SÈè`ÍJIS X 0208:1997Ì®1ÉŠ³êÄ¢éBvÆLµÄ¢Ü·B +W3C Ì XML Japanese Profile ÉÍAShift-JISÉUnicodeÖÌÏ·\ª¡ é|ÌLÚª èÜ·BXML Japanese Profile (Second Edition)ÅÍAUnicode ConsortiumÅöJ³êÄ¢éMicrosoft CP932ÌÏ·\ÉæécharsetÌŒÌ "x-sjis-cp932" ð "Windows-31J" ÉÏXµÄ¢Ü·B +MicrosoftÐÌ Global Dev ÅÍACodepage 932 ð "Japanese Shift-JIS" ÆLµÄ¢Ü·B +µ©µAShift-JISÉÍ éíÌȪ ÁÄA¿åÁƵœ±ÆªoOâG[ⶻ¯ÌŽöÆÈèÜ·BÈñÆ©ÈçÈ¢àÌŵ倩B +Perlͧä¶âi¶ðÜÞoCif[^ŷ糵ūéæ€ÉÝv³êÄ¢éÌÅAXNvgâeLXgðShift-JISÅ¢œç¢ÅâèÉÈé±ÆÍ èܹñB +µ©µAperlªXNvgððß·éÆ«ÍiÊíjoCgPÊŲ×éÌÅAShift-JISÌæ€È}`oCg¶ðÜÞÍ»ÌÜÜÅÍŒÚðūܹñB +œÆŠÎAShift-JISÅ ' ' Æ¢€¶ÍA16iÅ82 A0Æ¢€QoCgÅ\³êÜ·B±êð "\x82\xA0" Æ¢ÄàperlÉÆÁÄͯ¶Å·B±êªú{Ìicountryjú{êÌilanguagej¶Å éÆ©AShift-JISÅ©êÄ¢éicharsetjÆ©¢€îñÍDZÉàÜÜêĢܹñB +»ÌœßAShift-JISÅ«œ¢Æ«ÉÍAperlÌëððó¯È¢æ€É¢ÄâçȯêÎÈèܹñB»Ìz¶ÍAvO}ªµÄâçȯêÎÈèܹñB±Ì¶ÌLqÍA»Ìæ€ÈèÔð©¯ÄàAShift-JISðp¢é±ÆÉÓ`ª éÆlŠÄ¢élÉÍQlÉÈé©àµêܹñB +»ñÈèÔð|¯œÈ¢lÍA +Perl 5.8.xÈ~ðg€B +_Fperl5-porters@perl.org ÅT|[g³êÄ¢éB +_FÆÁÌlŠûª èA]Ìú{êÆÍeêÈ¢Æ±ëª éiàÁÆàA»Ì€¿µêÄCÉÈçÈÈé©àµêÈ¢jB +jperlðg€B +_FShift-JIS ð¶ÆµÄŒÚµ€±ÆªÅ«éB +_F»ÝAÛ·élª¢È¢B +¶R[hðUTF-8©EUC-JPÉÏ·µÄ©ç·éB +_FPerl 5.8.xÈ~ÅÈÄà®ì·éÏ·pÌW
[(.pm)âCu(.pl)ª¢ë¢ëüèÂ\B +_FShift-JISÙǫȢɵÄàA}`oCg¶ðVOoCg¶ÆæʹžAÆàÉê¶ÆµÄ·éÌÍÊ|Å éB + Æ¢€ÎðÆÁœÙ€ªæ¢Åµå€B±êçÌvOÍLŒÈÌÅAT¹Î·®©Â©éŵ倩çAüèæͱ±ÉÍŠµÜ¹ñB +ÈšA±Ì¶É©êÄ¢éªAÅà©ßçêÈ¢û@ÈÌÅA±±©çæÍA»ÌÂàèÅšÇݺ³¢B±Ìû@É¢Ĝ©^⪶¶œÆµÄàA»êÉ¢ČÌƱëÅ¿â·éÆAœÅ»ñÈâèûðµÄ¢éÌ©ÆA«ÁÆñï³êéŵå€B©Æ¢ÁÄAÉàu©È¢Åº³¢B +Shift-JISðgÁœÆ«É 調ÈiHjG[ +Shift-JISÉÍAæQoCgª [@-~]iASCII 10iÅ64-126jÌÍÍÉüéà̪ èÜ·B±êçÌASCII¶ÍAperlÉÆÁÄÁÊÈÓ¡ðà±ƪ éœßAµÎµÎG[ÌŽöÆÈèÜ·BShift-JISÅÍAQoCg¶ÌæQoCgÍA[\x40-\x7E\x80-\xFC])ÌÍÍÉ éœßAÀÉ188ªÌ63AñRªÌP̶ªœç©ÌâèðN±µŸéÆ¢ŠÜ·B +ÉAShift-JISðgÁœÆ«ÉN±èª¿ÈG[ƻ̎öðŠµÜ·BG[bZ[WÍperlÌá¢io[WâÇÌvbgtH[pÌàÌÅ é©jÉæèœÌᢪ é©àµêܹñB +G[ÉÈçÈÄàA¶»¯µœèAúÒµœæ€È®ìðµÈ©ÁœèÅA€Ü¢©È¢±Æª èÜ·B±ÌêAG[ªoÈ¢ªAŽöð©ªÅT³È¯êÎÈçÈÈéœßoOæè͵ε΢ïÅ·B +±±ÅÍG[ÉηéÎôÍñŠµÜ¹ñBÎôÍ ÆÅÜÆßÄ«Ü·B +ÈšA±±ÉͶR[hðEUC-JPɵÄàN±éæ€ÈâèâG[ÍŠµÜ¹ñBî{IÉAEUC-JPÈçN«È¢ªAShift-JISÌÆ«ÉÍN±éæ€È¿ÉÀèÜ·B +G[ÉÍÈçÈ¢¯Ç¶»¯·éiPj +áŠÎA"\Š" Æ© "\Í" Æ©¢€eª¶»¯ðN±µÜ·B±êçÍ "Š" Æ© "Í" ÉÈèÜ·B±êÍA"\" â "\"̶ÌæQoCgª \ Å éœßA_uNI[g¶ÌÅÍ̶ÌGXP[vð·é±ÆÉÈéÌÅA\Š 0x955C8EA6 Å ÁÄàANI[gÌÊÍ "\Š" 0x958EA6 ÆÈé©çÅ·B'\Š' Æ·êζ»¯ÍN±èܹñªAVONI[gÅàh°È¢¶»¯âG[ª èÜ·iájB +G[ÉÍÈçÈ¢¯Ç¶»¯·éiQj +áŠÎA"~\\500" Æ¢€eÅÍA\ ªEµÄµÜ¢Ü·B±êÍA'~\\500' â q(~\\500) ÈÇƵÄàh®±ÆªÅ«Ü¹ñB»êÍ \\ Æ¢€A±ª éÆ \ PÂÉÈÁĵ܀Ƣ€K¥ª é©çÅ·B +NI[gâNI[gZqÌÅÍA¶ñÉNI[gƯ¶¶ðÜßçêéæ€ÉA\ ÉæéGXP[vðt¯êÎNI[gÌI[¶ÅÍÈA¶ñÌêÆÝȵܷB»ÌœßA\\ ª \ ̶ð\·GXP[vÉÈèÜ·B±êÍNI[gÌn[EI[¶ðœÉµÄ௶±ÆÅ·B +G[ÉÍÈçÈ¢¯Ç¶»¯·éiRj +áŠÎA"Û\net" Æ¢€eª¶»¯ðN±µÜ·B±êÍ "Û¥ +et" Ìæ€ÉrÅüs³êĵܢܷB±êÍA"\" ÌæQoCgª \ Å éœßA_uNI[g¶ÌÅÍÌ 'n' Æí¹Ä\nÌ·Èí¿üs¶ð\·^¶ÆµÄðß³êé©çÅ·B +G[ÉÍÈçÈ¢¯Ç¶»¯·éiSj +áŠÎA"ø@ARGV" Æ¢€eª¶»¯ðN±µÜ·B±êÍA"@"iSpXy[XjÌæQoCgª @ Å éœßA_uNI[g¶ÌÅÍÌ ARGV Æí¹Ä "@ARGV" Æ¢€zñƵÄÏWJðs€©çÅ·B@ARGVÌæ€ÉKžè`³êéæ€ÈzñÈçAWJ³êÜ·ªAÊÌêÅÍG[ÉÈé©àµêܹñi»êÍðQÆjB +In string, @dog now must be written as \@dog (Perl 5.6.0ÜÅ) +u¶ñÌÅÍA@dogÍ¡Í\@dogƩȯêÎÈçÈ¢v +OáÅÝœæ€ÉASpXy[X "@"ÌæQoCgÍ @ Å éœßAãë̶Æí¹ÄzñÅ é©Ìæ€Éðßµæ€ÆµÜ·B"¢@dog" Ìæ€ÈêA@dog Æ¢€zñªè`³êÄ¢êλêðp¢ÄÏWJµÜ·ªAè`³êĢȢêAG[bZ[WðoµÜ·B +``now must be written as''u¡Í±€©È¯êÎÈçÈ¢vÆÍAPerl4ÜÅÍzñÌÏWJÍsíÈ©ÁœœßA"hoge@foo.bar" Ìæ€È«ûð·é±ÆªÅ«œÌŸªA¡ PerlÅÍ @foo ªWJ³êĵ܀ÌÅAÓð«N·éœßG[ðo·æ€ÉµÄ¢éæ€Å·iàµPerlªÌ©çzñÌWJðT|[gµÄ¢œçAG[ðo·±ÆÈAÙÁÄWJ·éŸ¯ŸÁœ©àµêܹñBàQÆjB +"¢@\dog" Æ·ê΢¢Æ¢€Ó©à èÜ·ªA\d ª^¶ÆµÄÁÊÓ¡ªÈ¢œßɀܢÌÅ ÁÄiPerl 5.6È~ÅÍAx Unrecognized escape \d passed through uF¯Å«È¢GXP[v \d ªn³êœvðø«N±µÜ·jAáŠÎ "Ô@\flower" ÌÆ«ÍA\f ªüy[W¶ÆµÄðß³êA¶»¯µÜ·B +Possible unintended interpolation of @dog in string (Perl 5.6.1È~) +¶ñÌÅA@dogª\ú¹žÉWJ³êé +OƯ¶A"¢@dog" Å·ªAPerl 5.6.1iActivePerl 626jÈ~ÅÍAè`³êĢȢzñÅàÙÁÄWJµÜ·Bzñ @dog ªWJ³êéÌÅA"¢\x81" Ư¶ÉÈèÜ·B +±êÍG[ÅÍÈAxÉÈèÜ·B +Can't find string terminator '"' anywhere before EOF +uI[¶ '"'ªt@CÌIè EOF ÜÅɩ©çÈ©Áœv +áŠÎA"Î\" Ìæ€ÈeÅÍA'\' ÌæQoCgª \ Å éœßA€µëÌ " ðGXP[vµÄµÜ¢Ü·B±ÌœßperlÍA»Ì " ÍNI[g¶ñÌI[¶ÆÍÝȳžÉA¶ñª³çɱÆlŠÄµÜ¢Ü·B±êÈ~AXNvgÌÉ " ̶ªSÜÜêȯêÎA±Ìæ€ÉG[ñðµÜ·B +qq{ "ú{ê" }Ìæ€ÈêÉàӵȯêÎÈèܹñB"{" ÌæñoCgÍ { ÈÌÅA±ÌÜÜÅÍ { }ÌlXgªžêĵܢA¯lÌG[ª¶µÜ·B +Bareword found where operator expected +uÌêªZqª ÁÄÙµ¢Êuɩ©Áœv +áŠÎAprint "<img alt=\"Î\\" height=115 width=150>"; Ìæ€ÈêA\" ÉæéøpÌGXP[vÍA\ ÌæQoCgÌ\ÌœßA\\ " Æ¢€gÝí¹ÉÈèAGXP[vªÅ¿Á³êĢܷB»ÌœßA±ÌeÍAperl©ç©éÆA"<img alt=\"Î\\" ÅIíÁĢܷB»ÌœßAeÌãÉAheight Æ¢€uÌêviNI[gÅÍÜêĢȢ¶ñjª éæ€ÉÝÄA±±ÉÍÌêÅÍÈAZqª é׫ÅÍÈ¢©HÆperlÍlŠÜ·B +Unrecognized character \x82 +uF¯³êÈ¢¶ \x82v +±êÍAñASCII¶â»ÌŒÌ¶ðuÌêvɵœÆ«ÉoébZ[WÅ·B"Î\" Ìæ€Èeª ÁÄA»Ì ÆÉ "ÈñÅࢢ¯Ç" Ìæ€Èeª ÁœÆ«AOáƯ¶R©çN±éàÌÅ·B +ÜœAq{}b`} Ìæ€ÈêÉàA'}' ÌæñoCgª } ÈÌÅA{ } ÌJbRÍ»±ÅIíÁĵܢA¯lÈG[ÉÈèÜ·B +}b`µÈ¢ÍžÈÌÉ}b`·éiPj +"J" =~ /|bg/ Í}b`µÜ·B»êÍA'|' ÌæñoCgª | ÈÌÅA/|bg/ Í /\x83|bg/ ÆÝȳêA\x83 Ÿ¯}b`·êÎ梩çÅ·B +}b`µÈ¢ÍžÈÌÉ}b`·éiQj +"Zí" =~ /Z/ Í}b`µÜ·B»êÍA'Z' ÌæñoCgª 'Z' Ÿ©çÅ·BæñoCgªAt@xbgÉÈé¶ÉÍÓªKvÅ·B +}b`·éÍžÈÌÉ}b`µÈ¢iPj +"^]Æ" =~ /^]/ Í}b`µÜ¹ñB»êÍA'^' ÌæñoCgª '^'ÈÌÅA/^]/ Í /\x89^]/ ÆÝȳêA¶ñÌnß ^ ÌOÉ \x89 ÍÈ¢©çÅ·B +Search pattern not terminated +uT[`p^[ªI¹µÈ¢v +±êÍA/\/ Ìæ€ÉAæñoCgª \ Å é¶ÅT[`p^[ðIíç¹æ€ÆµœÆ«ÉN±èÜ·B}b`ZqÌI[¶ / ðGXP[vµÄµÜ€ÌÅAT[`p^[ª³çÉæɱæ€Éðß³êÜ·B»ÌæÉà€êx/Í èÜ·©H + ÁœÆ±ëÅAÊÌG[ª¶·éŵå€B +Substitution replacement not terminated +uu·ìÌu·¶ñªI¹µÈ¢v +u·ZqÍ s/PATTERN/REPLACEMENT/Ì`®ðÆçËÎÈèܹñBµ©µ s/\/ /; Ìæ€ÉAæñoCgª \ Å é¶ÅPATTERNªðIíç¹æ€ÆµœÆ«É±ÌG[ªN±èÜ·B}b`ZqÌI[¶ / ðGXP[vµÄµÜ€ÌÅAPATTERNª³çÉæɱæ€Éðß³êÜ·B»ÌœßperlÍAPATTERNÍ \/ ̪ŠéÆlŠARÔÚÌ/ÌæÉREPLACEMENTªª éÉá¢È¢Æv€ÌÅ·ªA»ÌæÉà€êx/Í èÜ·©H + ÁœÆ±ëÅAÊÌG[ª¶·éŵå€B +unmatched [ ] in regexp +u³K\»É}b`µÈ¢ [ ] ª év +áŠÎA/v[/ ÅÍG[ªN±èÜ·B»êÍ '[' ÌæñoCgª [ ÈÌÅA/v[/ Í /v\x81[\x83\x8B/ ÆÝȳêAperlͶNXª éÌÅÍÈ¢©Æv¢Ü·Bµ©µ¶NXÌI¹ðŠ· ] ª©Â©çÈ¢ÌÅG[ÉÈèÜ·B +G[ÉÍÈçÈ¢¯Ç¶»¯·éiTj +áŠÎAlc('ACEGI')ÍA'acegi'ðԵܷBShift-JISÌQoCg¶ÌÉÍAæQoCgªASCIIÅpÉœéà̪ èÜ·BÚµÍAt@xbgÌå¶Æ¬¶ð²º³¢B +G[âÔá¢ðh®Îô +ÈãÌæ€ÈG[ðh®Éͳ܎ÜÈû@ªlŠçêÜ·BáŠÎA"\\Š" Ư΢¢ÈÇÆ¢€ñĪ èÜ·Bà¿ëñ»êÅà©Ü¢Ü¹ñBµ©µ»ÌœßÉÍÇ̶ÌãÉ \ ðüêê΢¢©ðméKvª èÜ·B»êͶR[h\ð©êÎêÅŸç©Å·B +cÈÇÆ¢€Ê|ȱƪêÉÈçÈ¢lA¶R[h\Èñ©iÈÆàâèÉÈéæ€È¶ç¢ÍjÃLµÄµÜŠÎ¢¢Æ¢€æ€ÈlÉÆÁÄÍAm©É»êÅðÉÈéÆv¢Ü·Bµ©µA»Ìæ€ÈlÉÍA±ñÈy[Wð©ÉéKvàq}àȢŵå€B +»±ÅA±Ìæ€Èy[WðíŽíŽ©Ééæ€ÈlÍA¶R[h\𢿢¿²×œÈ¢ÐÆŸÆŒèµÜ·BÊÉ»€Ÿ©çÆ¢ÁÄñï³êé±ÆÍ èܹñBµ©µAèÔðÉµÞ ÜèÔáÁœvOðœCÅìÁÄ¢ÄÍAçÉN[pCðÔ¯çêÄàdû èܹñB +¶ñeÌìèû +æmÁÄš©ËÎÈçÈ¢±ÆÍA\ Æ¢€GXP[vp̶ÍAÏWJâ^¶ÌðßæèžÁÆOÌiKų܎ÜÈe¿ðyÚ·Æ¢€±ÆÅ·B»ÌœßAÇ€µœçf[^ðmÀÉÏÌÉûßçêé©ðlŠéKvª èÜ·BÏÌàÉûßĵ܊ÎAPerlªf[^ðKØÉǵÄêÜ·BæmçêÄ¢é $str = "\Š" ̶»¯àAÏ$strÉãü·éÈOA_uNH[gÅÍñŸ_Å·Åɶ»¯µÄ¢éÆlŠé׫ŷB·Åɶ»¯µœf[^ðãüµÄAD¢ÊªŸçêéÍžª èܹñB +qAhL
gÍÀS«Ì¢ð@Å·BœŸµAI[¶ñðVONH[gÅÍñÅâçÈÄÍÈèܹñB_uNH[gÅÍñŸèANH[gðt¯È©ÁœèÅÍA\ú¹ÊÏWJâ^¶Ìðßðh®±ÆªÅ«Ü¹ñB +VONH[gÅI[¶ñðÍñŸqAhL
gÅÍAÏWJâ^¶ÌðßÍœàN±èܹñBœŸAI[¶ñi±ÌêÍ "\nEOF\n"jðT·±ÆŸ¯ðs¢Ü·BqAhL
gðg€Æ¶ñÉüs¶ªÂ«Ü·ªAchompÅÆ¢¢Åµå€B +ÌáÍ $str = '±±ÉeLXgð' Ư¶æ€É«Ü·ªA¶ñÌàeÉæÁÄâèªN±èܹñB¢œÆšèÉeðãüÅ«éÆúÒÅ«Ü·B +TvR[h +chomp($str = << 'EOF'); +±±ÉeLXgð +EOF + +$src = << 'EOF'; + $path = "C:\\path\\file"; + open FH, $path; +EOF + +œÌ¶ñðêxÉì蜯êÎAsplitŪ·éÆeÕÉìêÜ·B +TvR[h +($name, $career, $age, $memo) = split "\n", << 'EOF'; +cêY +vO} +O\Ü +åªDšÅ éB ðÍ ÜèÛÜÈ¢B +EOF + +à€µÈÉ«œ¯êÎAó¶A\iQoCg¶ÉÜÜêÄ¢éÌÍ\íÈ¢jAšæÑJbRðÜÜȢƢ€ðÅAqw() ðg€±ÆªÅ«Ü·BáŠÎA@str = qw(\Š Î\ );Ìæ€ÉóðüêÄJbRÌGXP[vðh¬Ü·B@str = qw(\Š Î\);Ìæ€ÉóðüêÈ¢ÆG[̳ŷB +PÂ̶ñðìéÅàA¶ÓðÛJbRÅÍñÅXgReLXgðŠ·©AEÓðXCXɷ驵ȯêÎÈèܹñB±êÍAi»óÅÍjqw// Í split(' ', q//) ̪LƵÄÀµÄ¢é©çÅ·BÈšAPerl 5.6ÅÍXgÆ¿ÉÈÁÄ¢éæ€Å·B +TvR[h +($str) = qw(SO\ ); + $str = (qw/SO\ /)[0]; + $str = qw/SO\ /; # Perl 5.6 + +³K\»Æ}b` +³K\»Ì^¶Íœ¢ÌÅA³K\»ÌÉShift-JIS̶ñðß±ÞÌÍŸôÅÍ èܹñBáŠÎA/\QÎ\/ ÅÍG[ÉÈèÜ·B±êÍA/ / ÌÍÍÌèª^ÁæÉsíêA»Ì_ÅG[ª¶·éÌÅA\Q ÌøÊðyÚ·±ÆªÅ«È¢©çÅ·BÜœA/\QÎ\\E/ ÍIs«Ü¹ñB±êÍAÎ\\E Æ¢€¶ñðÜÞàÌɵ©}b`µÜ¹ñB±êÍA\\ Æ¢€A±ª éœßA\E ªF¯³êÈ¢©çŵå€iœÔñjB +»ÌœßAÏÉüêÄA}b`Zqâu·ZqÌÅWJ³¹éÆæ뵢ŷB±ÌÆ«ú{ê¶ñÍ\ßquotemeta ÖŵĚ«Ü·B +TvR[h +$pat = quotemeta +(qw/ \ /)[0]; +$str =~ /$pat\d+/; # \1, \2, ..ÈÇÉ}b` + # µ©µ $str = '\\1' Åà}b`·éi±ÌâèÍãqj + +ãÌæ€È«ûÍm©ÉX¢Å·ËBNI[gÌÅ \Q \E ðg€ÍA³µ¢¶ñªüÁÄ¢éÏÆêÉÈçâèªN±èܹñB±€·é±ÆÅA\Q \E ÌÍͪŸmÉÈé©çÅ·B³µ¢¶ñÌìèûÍAOqÌeÌìè©œðQlɵĺ³¢B +TvR[h +$pat = "(?:\Q$str1\E|\Q$str2\E)*"; +$str =~ /$pat/; + +# ÀÍã̶Í̶ƿB +# $pat = "(?:" . quotemeta($str1) . "|" . quotemeta($str2) . ")*"; + +eðNH[gÌÉŒÚß±ÞÆ€Üs©È¢±Æª èÜ·B»êÍAperlª \E Æ¢€^¶ð©µæ€Æ¢€ÌðAShift-JIS¶ªW°éœßÅ·B +"\Q\\E"ÅÍA\EÉ}b`·é³K\»ÉÈèÜ·B\ÌæñoCgÌ \ ÆÌ \ªí³éÌÅAperlÉÍ\Q \x95 \\ EÌgÝí¹Å éæ€ÉvíêÜ·B \QÌìpÌÊÍ\\x95\\x5cEÉÈèÜ·B»ÌœßA\EÉ}b`µÜ·B +"\Q\"Íǀŵå€B±ÌêÍA" " ÌÍÍðßéÆ«ÉA\ÌæñoCgªãÌNH[gðGXP[vµÄµÜ€ÌÅA¶ñÌÍͪúÒµœæ€ÉÍèÜçžAG[ÉÈèÜ·B±ÌG[Í\QÌøÊðl¶·éOɶ·éÌÅAh¬æ€ª èܹñB +"\Q\\\E"Íǀŵå€Bm©ÉShift-JISÅÍâè èܹñBµ©µ¯¶XNvgðEUC-JPâUTF-8ÉÏ·µœÆ«ÉÍâèª èÜ·B\\EÆ]ªÈQ¶ª é¶ñÅÈ¢Æ}b`µÜ¹ñBÇ¿çɵëA\ðDZÉYŠé©ðlŠéKvª éÌÅA±±Ìï|ɢܹñB +³K\»ÍáŠÎAÌæ€ÉµÜ·Bà¿ëñ±êÍShift-JISÌÝÉLøÅ·B + $digit = '(?:[0-9]|\x82[\x4F-\x58])'; # iŒpÆSpj + $upper = '(?:[A-Z]|\x82[\x60-\x79])'; # At@xbgå¶iŒpÆSpj + $lower = '(?:[a-z]|\x82[\x81-\x9A])'; # At@xbg¬¶iŒpÆSpj + $space = '(?:[\ \n\r\t\f]|\x81\x40)'; # ó¶iŒpÆSpj + $ascii = '[\x00-\x7F]'; # ASCII¶ + + # SpœŒŒi÷_EŒ÷_ExèðÜÞj + $hiraZ = '(?:\x82[\x9F-\xF1]|\x81[\x4A\x4B\x54\x55])'; + + # SpÐŒŒi·¹E÷_EŒ÷_ExèðÜÞj + $kataZ = '(?:\x83[\x40-\x7E\x80-\x96]|\x81[\x5B\x4A\x4B\x52\x53])'; + + # ŒpÐŒŒiŒp·¹EåÇ_ðÜÞj + $kataH = '[\xA1-\xDF]'; + + $onebyte = '[\x00-\x7F\xA1-\xDF]'; + $twobyte = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + $char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + + # JIS¶ + $all_JIS = '(?:[\x00-\x7f\xa1-\xdf]|'. + . '\x81[\x40-\x7e\x80-\xac\xb8-\xbf\xc8-\xce\xda-\xe8\xf0-\xf7\xfc]|' + . '\x82[\x4f-\x58\x60-\x79\x81-\x9a\x9f-\xf1]|' + . '\x83[\x40-\x7e\x80-\x96\x9f-\xb6\xbf-\xd6]|' + . '\x84[\x40-\x60\x70-\x7e\x80-\x91\x9f-\xbe]|' + . '\x88[\x9f-\xfc]|\x98[\x40-\x72\x9f-\xfc]|\xea[\x40-\x7e\x80-\xa4]|' + . '[\x89-\x97\x99-\x9f\xe0-\xe9][\x40-\x7e\x80-\xfc])'; + + # x_è`¶ + + # NECÁê¶ + $NEC_special = '(?:\x87[\x40-\x5d\x5f-\x75\x7e\x80-\x9c])'; + + # NECIèIBMg£¶ + $NEC_IBM_ext = '(?:\xed[\x40-\x7e\x80-\xfc]|\xee[\x40-\x7e\x80-\xec\xef-\xfc])'; + + # IBMg£¶ + $IBM_ext = '(?:[\xfa-\xfb][\x40-\x7e\x80-\xfc]|\xfc[\x40-\x4b])'; + + +Shift-JISÅ}b`ðs€ÉÍAQÂÌâèª èÜ·B +æñoCgªASCIIÌÌæÉü鶪 éÌÅAASCIIðÜÞp^[É}b`·éÂ\«ª éB + é¶ÌæñoCgÆ̶ÌæêoCgªP¶Å é©Ìæ€É}b`µÄµÜ€B +ãÒÍEUC-JPÅàN±è€éâèÅ·iUTF-8ÈçN±çÈ¢ªA¡Í»êªâèÈÌÅÍÈ¢jBµ©µOÒÍEUC-JPÅÍN±çÈ¢ªAShift-JISÅÍN±è€éâèÅ·B±êçðh®û@ÍAǯ¶±ÆÅ·ªA³K\»ÌÉAíÉæªðÜܹé±ÆÅ·B +TvR[h +# 檩ç}b` +$str =~ /^$char*?(?:$pat)/; + +ö©çÌ}b`ÅÍ€Üs©È¢±Æª èÜ·B"E" =~ /E$/ðlŠêÎ\ªÅµå€BÜœA"\x8E" x 30 . "E"Í$str = "E"Å éªA"\x8E" x 31 . "E"Í$str = "E"Å èÜ·©çAShift-JIS¶ñðãë©çØ誯éKØÈû@ÍÈ¢ÆlŠçêÜ·B +ÈÆàAQoCg¶ð\¬µÈ¢oCg [\x00-\x3F\x7F] ª©Â©éÜÅAÉ[ÈêͶñÌÅÜÅXLµÈ¢Æí©çžAµ©àãÇÝ lookbehind ̳K\» (?<=PATTERN)Í¡ÌAsè·Éūܹñi(?<=(?:\A|[\x00-\x3F\x7F])$char*) ÆÍÅ«È¢jÌÅA檩ç¶PÊÅÎçµÄ©ç·é̪AÇÍÈÖÈÌ©àµêܹñB +O[o}b` +O[o}b` /g ÌêÍA\Gðg¢Üµå€B\GÍOñ}b`µœªÌöðwµÜ·B +ÌáÅÍAu·³êȢ̪]ܵ¢ÌÅ·ªA\GªÈ¢ÌÅA檩çJnµÄ¶ñSÌÜÅÑÄ}b`µÈ©Áœ ÆAüßÄ檩çPoCgiñŸÊu©çXLðÄJ·éÌÅAžêœÊuÈÌÉ}b`µœÆlŠÄµÜ¢Ü·B\GðgíÈ¢ÆAÔáÁœÊuÉ}b`·é©àµêÈ¢€ŠÉA]vÈÄžð·éÌÅAÔà©©èÜ·B +TvR[h + $str = 'EE'; + $pat = 'E'; + $str =~ s/\G($char*?)($pat)/${1}E/og; + # 'EE' ÌÜÜi³µ¢jB + +\Gðt¯È¢ê + + $str = 'EE'; + $pat = 'E'; + $str =~ s/($char*?)($pat)/${1}E/og; # 'E' ª êÎ 'E' Éu· + print $str; + # 'EE' ÉÈÁĵ܀iš©µ¢jB + +@@@@EE +PñÚ@šššš/šššš/ i}b`µÈ¢j +QñÚ@|šššË||||||||| i}b`µœÌÅu·j +RñÚ@|||||||||šššš/ i}b`µÈ¢j +SñÚ@||||||||||šššË i}b`µœÌÅu·j + +@}áF š@$charªQoCg¶É}b` +@@@@@/@$charªPoCg¶É}b` +@@@@ Ë@$patª}b` +@@@@@|@XLÌÍÍO + +œŸµAp^[ª[¶É}b`·éêÉÍAÓªKvÅ·BÌáÍAuAvÌOÉ 'Z' ðüêéàÌÅ·BæPáͶ̞êi'A' : 0x8341ÉεÄ'A' : 0x8B8341ªžêÄ}b`·éjðh¢Å¢Ü¹ñBæQáÍAãÌû@Åužêvðh²€ÆµœÌÅ·ªAZ ÖÌu·ªA±µÄN±ÁĢܷB +±êÍæRáÌæ€É·éKvª èÜ·B±êÍAæQáÅÍuȺHvÉ¢œæ€ÉAu·³êé©çÆlŠçêÜ·B +TvR[h +$str = "ACEGAACEAA"; + +print +($temp = $str) =~ s/(?=A)/Z/g, $temp; + +print +($temp = $str) =~ s/\G($char*?)(?=A)/${1}Z/g, $temp; + +print +($temp = $str) =~ s/\G(\A|$char+?)(?=A)/${1}Z/g, $temp; + +Ê +5 ZACEGZAZACEZAZA +7 ZACEGZZAZZACEZZAA +4 ZACEGZAZACEZAA + +ȺH + A C E G A A C E A A +1 \G Z +2 \G$char$char$char$char Z +3 \G Z +4 \G$char Z +5 ȺAȪ + +ÂÜèAO[o}b`ÅÍA}b`ª[¶ÅÈ¢p^[ÌOÉÍ\G($char*?)ðA[¶Å ép^[ÌOÉÍ\G(\A|$char+?)ðüêéKvª èÜ·B +œŸµA±êÅà³µiHj}b`³¹çêÈ¢êª èÜ·B +TvR[h +$str = "0123000123"; + +print +($temp = $str) =~ s/0*/Z/g, $temp; + +print +($temp = $str) =~ s/\G($char*?)0*/${1}Z/g, $temp; + +print +($temp = $str) =~ s/\G(\A|$char+?)0*/${1}Z/g, $temp; +__END__ + 9 ZZ1Z2Z3ZZ1Z2Z3Z +14 ZZ1ZZ2ZZ3ZZ1ZZ2ZZ3ZZ + 7 Z1Z2Z3Z1Z2Z3Z + +±êÍAp^[ª[¶É}b`·éàÌÅ éÆA/gª»ÌêųÀÉ«¥ÝµÄI¹µÈÈéÌðh®œßAperlÍA}b`ð§IÉißÄ¢éÌÅ·ªicf. perlre, Repeated patterns matching zero-length substringjA±ÌißûÌ^iµ©àoCgPÊÅÍÈA¶PÊÅiÞàÌjªA\G($char*?)â\G(\A|$char+?)ÅÍA€ÜÅ«È¢©çÅ·BàÁÆà±€¢€}b`ð·é±ÆÍAÙÆñÇÈ¢ÆlŠçêÜ·ÌÅACÉ·éKvÍȢ̩àmêܹñi¯ÉµÝjB +At@xbgÌå¶Æ¬¶ +Shift-JISÌQoCg¶ÌÉÍAæQoCgªASCIIÅpÉœéà̪ èÜ·B»ÌœßAÖ uc, lc âA^¶ \U, \LªQoCg¶ÌêðÏ·µÄµÜÁœèiµ©µÖ ucfirst, lcfirst â ^¶ \u, \l ÍâèÆÈçÈ¢jAm//i â s///iÈÇÌ /iCüqÉæÁÄံÈÌÉ}b`µÄµÜÁœè·é±Æª èÜ·B +Shift-JIS¶ñÉÜÜêéASCIIÌpðå¶ÜœÍ¬¶ÉµŠœ¢ÈçAáŠÎAÌæ€ÈTu[`ðìêÎÀ»Å«Ü·B +TvR[h +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + +lc("PERLvO~O"); # 'perlvo~o' +tolower("PERLvO~O"); # 'perlvO~O' + +sub tolower { + my $str = $_[0]; + $str =~ s/\G($char*?)([A-Z]+)/$1\L$2/g; + $str; +} + +sub toupper { + my $str = $_[0]; + $str =~ s/\G($char*?)([a-z]+)/$1\U$2/g; + $str; +} + +P[X³Ì}b` /i ÌêÍAáŠÎ 'G'ÌæñoCgÍ 'G' Å èA'g'ÌæñoCgÍ 'g' Å é±Æ©çA'G' =~ /g/iÍ}b`µÜ·BÅ·©çAShift-JISųmÈ}b`𵜯êÎA/iCüqÍg€±ÆªÅ«Ü¹ñB +©íèÉA¶ñÉÜÜêéAt@xbgiñoCg¶ÌæQoCgÉ éàÌðjð¬¶iÜœÍå¶AÇ¿ç©jÉêµÄ}b`³¹Ü·BtolowerÌè`Íã𲺳¢B +TvR[h +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + +$lcstr = tolower($str); +$lckey = tolower(quotemeta $key); + +if ($lcstr =~ /^$char*?$lckey/) { + print "matched"; +} +else { + print "not matched"; +} + +ÜœÍßÝCüq (?ismx-ismx) ðp¢ÄàD¢ÊðŸçêÜ·B +TvR[h +"æPñPerluk̲Äà" =~ /^$char*?PERLuK/i # }b`·éi¢éj +"æQñPerluk̲Äà" =~ /^$char*?((?i)PERL)uK/ # }b`µÈ¢iǵj +"æRñPerluK̲Äà" =~ /^$char*?((?i)PERL)uK/ # }b`·éiǵj + +SpQoCgAt@xbgÌP[X³ÍAIðÉæèÀ»Å«Ü·iªAâÁÏèÏjB'`'ÌæQoCgª '`' ÈÌàA¿åÁÆÓÅ·im`` ÈÇÌÆ«vœIG[ÉÈéBœŸµobNNH[gðg€Ó¡ÍÁÉÈ¢jBŽ¥IÉÍeð}b`Zqâu·ZqÉŒÚßÞÌÍ𯜢ŷB +TvR[h +/(?:o|)(?:d|
)(?:q|)(?:k|)/; + +»ÌãíèɱñÈTu[`ðìÁÄÝÄà梩àµêܹñB +TvR[h +$CharRE = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + +$pat = make_regexp_ignorecase("odqkuK"); +print "æTño
uKï" =~ /^$char*?$pat/ ? "OK": "NOT"; + +sub make_regexp_ignorecase { + my $str = $_[0]; + $str =~ s/\G([A-Za-z]+|$CharRE)/ + my $c = ord $1; + if($c == 0x82) { + my $v = vec($1,1,8); + 0x81 <= $v && $v <= 0x9A ? sprintf('\\x82[\\x%2x\\x%2x]', $v, $v-33) : + 0x60 <= $v && $v <= 0x79 ? sprintf('\\x82[\\x%2x\\x%2x]', $v, $v+33) : + quotemeta($1); + } + elsif(0x41 <= $c && $c <= 0x5A || 0x61 <= $c && $c <= 0x7A) {"(?:(?i)$1)"} + else {quotemeta($1)} + /geo; + $str; +} + +·¢¶ñÉηé³K\»õ +³K\»ÍAPerl ÉÆÁÄ©¹È¢¶ÝÆ¢ŠÜ·Bµ©µ³K\»Ì§ÀƵÄA*, +, {min,max} ÈÇÌÊwèqª}b`ðJèÔ¹éñÌãÀÆ¢€âèª èÜ·B(Ú×Í perlre QÆ̱Æ)B»ÌœßA$char*? Æ¢€³K\»ÉÍA믫ª èÜ·B +áŠÎAÌæ€È}b`OðlŠÄ©Üµå€B$strÍAu vª10A±µœ ÆÉAuACABCvªA³êœ¶ñÅ·B±Ìæ€È¶ñiœŸµAuw xª10A±vÆ¢€±Æͪ©çžACÓÌ Shift-JIS eLXgÅ ë€Æ¢€±Æɵܷj©çAŒpAt@xbgªA±µœªð©Â¯œ¢ÆµÜµå€B·éÆA¡ÜÅÌlŠû©ç·éÆAÌæ€É·êÎæ¢ÆvíêÜ·B +TvR[h +my $char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; +my $str = (' ' x 100000) . 'ACABC'; +$str =~ /^$char*?([A-Z]+)/o; +print $1; + +µ©µA±êÍA«ÉæÁÄÍAå«ÈG[ðø«N±µÜ·BáŠÎAWindows 98ãÅ Active Perl 522 ðp¢œêAError: Runtime exception Æ¢€ Perl ÌG[ÉÈèܵœBÜœAWindows 98ãÅVC++ 6.0ÅRpC³êœ Perl 5.6.1 ŸÆAu±ÌvOÍs³ÈðsÁœÌŧI¹³êÜ·B`vÈÇÆ¢ÁœG[ÉÈèܵœB +±Ìæ€Èâèðū韯h®œßÉÍAÌæ€ÉµÜ·BÂÜèA¶ñÌ檩ç²×Ä¢êAñoCg¶Ì¶«EðÔáŠéÌÍAñoCg¶ÌæêoCgÌŒãð¶«EÆëF¯µœŸ¯Å·BShift-JISÅÍAñoCg¶ÌæêoCgÍA[\x81-\x9F\xE0-\xFC] Ÿ¯Å·B é¢ÍAEUC-JP ÉÏ·Â\ÈÌ柯ðl¶·êÎA[\x81-\x9F\xE0-\xEF] Ÿ¯Æ¢€±ÆªÅ«Ü·B»êÈOÌoCgÌŒãÍAáŠÎA0x41 ÌŒãÍA'A' ÌŒã©A'A' ÌŒã©Íª©èܹñªAm©É¶«EÉÈèÜ·B]ÁÄA[\x81-\x9F\xE0-\xFC]+ iÜœÍ [\x81-\x9F\xE0-\xEF]+ jÌoCgiñoCg¶jªA±·éƱ럯ÉÓ·êÎ梱ÆÉÈèÜ·B +±ÌœßAȺÌæ€ÉA^$char*? ÌãíèÉ $Apad ðg¢A\G$char*? ÌãíèÉ $Gpad ðp¢êÎAêoCg¶©AñoCg¶Ì€¿æñoCgª [\x40-\x7E\x80\xA0-\xDF] ÅIíéà̪AÈÆàKÈÔuÅiãÀÉBµÈ¢€¿Éjo»·êÎAG[ÉÈçžÉ·é±ÆªÅ«Ü·BimŠIÈâèÅ·ÌÅA®SÅÍ èܹñBj +TvR[h +# êñŸ¯}b` +my $Apad = '(?:(?:\A|[\x00-\x80\xA0-\xDF])(?:[\x81-\x9F\xE0-\xFC]{2})*?)'; +my $str1 = (' ' x 100000) . 'ACABC'; +$str1 =~ /$Apad([A-Z]+)/o; +print "$1\n"; # "ABC" Æ\Š³êéB + +# O[o}b` +my $Gpad = '(?:(?:\G|[\x00-\x80\xA0-\xDF])(?:[\x81-\x9F\xE0-\xFC]{2})*?)'; + +my $str2 = ' ' x 100000 . 'ACABC'. 'š' x 100000 . 'XYZ'; +my @array = $str2 =~ /$Gpad([A-Z]+)/go; +print "@array\n"; # "ABC XYZ" Æ\Š³êéB + +OÌÏ· +x_è`¶â[Uè`¶ðÜÞ¶ñðŒÌ«ÅàpÅ«éæ€É·éÉÍAKØÈÏ·ªKvÅ·i³_AÜÁœ¯¶ÌÌpÍÙÆñÇ]ßžAš»çÍÞµœ¶â¶ñÉÏ··é±ÆÉÈéŵå€jB±êÍPerlÅÍu·Zq s/// ðgŠÎärIeÕÉÀ»Å«Ü·B + 究ßAÇÌOðǀϷ·é©ðè`·éÏ·e[uðpÓµÈÄÍÈèܹñB±êÍPerlÅÍnbV
ɵĚƻÌã̪yÉÈèÜ·B±±ÅÍA'w932_gai.txt'Åè`·éAWindows codepage-932R[hÉîâœ@í˶¶ÌiªIjÏ·e[uðg€±ÆɵܷB +ÌR[hÅÍAP¶ÃÂ}b`³¹A»Ì¶ªÏ·nbV
ÌL[É êÎηél̶ñÉu·µA»€ÅȯêλÌÜÜcµÜ·B +TvR[h +require 'w932_gai.txt'; # %tableÌè`is®SIj + +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + +$str =~ s/($char)/exists $table{$1} ? $table{$1} : $1/geo; + +¯lÈÍA¬Ìæ€È«ûÅàÅ«Ü·ªAOÉ}b`·é³K\» $gaijiðpÓ·éKvª èÜ·Bžêœ}b`ðµÈ¢œßÉA±¿ç̳K\»ÉÍ \G ªKvÅ·BáŠÎA$str = '@';ÌãëQoCgÍ "\x87\x40" Å·ªA±€·êÎ}b`ªžêéSzª èܹñBÜœAñ~£è}b` ($char*?)ðgŠÎ $char ªOÉ}b`µÈ¢æ€ÏX·éKvÍ èܹñB +TvR[h +require 'w932_gai.txt'; # %tableÌè`is®SIj + +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; +$gaiji = '(?:[\x87][\x40-\x9c])'; + +$str =~ s/\G($char*?)($gaiji)/$1$table{$2}/g; + +CP932d¡è`¶ÌÏ· +Microsoft Windows ú{êÅÅêÊIÉgp³êÄ¢éR[hy[W 932 (CP932) ÅÍAô©̶ªd¡µÄè`³êœóÔÉÈÁĢܷB±±ÅA¶ªd¡è`³êÄ¢éÆÍAUnicode̯¶ÊuÉÎt¯çêÄ¢é±ÆƵܷB +áŠÎACP932 -> Unicode -> CP932 ÌÅÏ·³êéÆAd¡è`¶ÍAÇê©êÂɵŠçêÜ·B±ÌDæÊÍ JIS X 0208, NECÁê¶ (13æ)AIBMg£¶ (115`119æ)ANECIèIBMg£¶ (89`92æ) ÌÅ·BêáƵÄA'æ' ÌêANECÁê¶Ì "\x87\x9A" â IBMg£¶Ì "\xFA\x5B" ÍAJIS X 0208 Ì "\x81\xE6" ÉÈèÜ·B +µ©µACP-932 ÌeLXgAd¡è`¶ªÇê©ÉµÁĢȢ±Æª èÜ·BáŠÎ "\x87\x9A" â "\xFA\x5B" ªÜÜêÄ¢éÆAeLXgðÚÅ©éÆᢪȢÌÉA"\x81\xE6" ÅõµÄà©Â¯çêÈ¢±ÆÉÈèÜ·B +d¡è`¶ðµŠéW
[ƵÄAShiftJIS/CP932/Correct.pm ª èÜ·BüèÆg¢ûÍPerlÌy[WÉßêΩ©èÜ·B +ÜœAShiftJIS/String.pm Ì strtr() ÜœÍ trclosure() ðg€û@à èÜ·BüèÆg¢ûÍPerlÌy[WÉßêΩ©èÜ·B +TvR[h + +# (1) $necJIS -> $jisNEC (9Î) + $necJIS = "\x87\x90\x87\x91\x87\x92\x87\x95\x87\x96\x87\x97\x87\x9A\x87\x9B\x87\x9C"; + # NECÁê¶Ì€¿AJIS¶ÉÏ·³êé׫ñ¿ + $jisNEC = "\x81\xE0\x81\xDF\x81\xE7\x81\xE3\x81\xDB\x81\xDA\x81\xE6\x81\xBF\x81\xBE"; + # JIS¶Ì€¿ANECÁê¶Éd¡è`³êÄ¢éñ¿ + +# (2) $necibmJIS -> $jisNECIBM (1Î) + $necibmJIS = "\xEE\xF9"; + # NECIèIBMg£¶Ì€¿AJIS¶ÉÏ·³êé׫ñ¿ + $jisNECIBM = "\x81\xCA"; + # JIS¶Ì€¿ANECIèIBMg£¶Éd¡è`³êÄ¢éñ¿ + +# (3) $ibmJIS -> $jisIBM (2Î) + $ibmJIS = "\xFA\x54\xFA\x5B"; + # IBMg£¶Ì€¿AJIS¶ÉÏ·³êé׫ñ¿ + $jisIBM = "\x81\xCA\x81\xE6"; + # JIS¶Ì€¿AIBMg£¶Éd¡è`³êÄ¢éñ¿ + +# (4) $ibmNEC -> $necIBM (13Î) + $ibmNEC = "\xFA\x4A-\xFA\x53\xFA\x58\xFA\x59\xFA\x5A"; + # IBMg£¶Ì€¿ANECÁê¶ÉÏ·³êé׫ñ¿ + $necIBM = "\x87\x54-\x87\x5D\x87\x8A\x87\x82\x87\x84"; + # NECÁê¶Ì€¿AIBMg£¶Éd¡è`³êÄ¢éñ¿ + +# (5) $necibmIBM -> $ibmNECIBM (13Î) + $necibmIBM = "\xEE\xEF-\xEE\xF8\xEE\xFA\xEE\xFB\xEE\xFC"; + # NECIèIBMg£¶Ì€¿AIBMg£¶ÉÏ·³êé׫ñ¿ + $ibmNECIBM = "\xFA\x40-\xFA\x49\xFA\x55\xFA\x56\xFA\x57"; + # IBMg£¶Ì€¿ANECIèIBMg£¶Éd¡è`³êÄ¢éñ¿ + +# (6) $necibmCJK -> $ibmCJK (360Î) + $necibmCJK = "\xED\x40-\xEE\xEC"; + # NECIèIBMg£¶Ì¿ + $ibmCJK = "\xFA\x5C-\xFC\x4B"; + # IBMg£¶Ì¿ + +use ShiftJIS::String qw(trclosure); + +# Ï·pN[W̶¬ +$correctCP932 = trclosure( + $necJIS.$necibmJIS.$ibmJIS.$ibmNEC.$necibmIBM.$necibmCJK, # from + $jisNEC.$jisNECIBM.$jisIBM.$necIBM.$ibmNECIBM.$ibmCJK # to +); + +$result = $correctCP932->($source); # $source ðÏ·µÄ $result ðŸé + +¶ðŠé +Shift-JIS¶ñ̶ðŠéÉÍA}b`Zqðp·éÈçXJ[ReLXgÅŠœûªá±¬©ÁœÅ·B»êæèAu·ZqðpµœÙ€ª¬¯éÆí©èܵœB +àÁÆàXSÅ¢œÙ€ªžÁƬ©ÁœÅ·BÜ AXSUBͳÉpµÈÄàæ¢Åµå€B +TvR[h +use Benchmark; + +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; +$s = "¿ \0A±CeXg -"; + +timethese (100000, { + le => q{ + ($str = $s) =~ s/$char/0/go; + $le = length $str; + }, + sg => q{ + $sg = ($str = $s) =~ s/$char//go; + }, + ab => q{ + $ab = 0; + $ab++ while $s =~ /[^\x81-\x9F\xE0-\xFC]|../g; + }, + ar => q{ + $ar = @{[ $s =~ /$char/go ]}; + }, + gr => q{ + $gr = grep defined, $s =~ /$char/go; + }, + wh => q{ + $wh = 0; + $wh++ while $s =~ /$char/go; + }, + sj => q{ + $sj = sjslen($s); + }, + xs => q{ + $xs = sjlength($s); + }, +}); + +sub sjslen { + my($str,$len,$i,$c,$blen); + $str = shift; + $blen = length $str; + while ($i < $blen) { + $c = vec($str, $i, 8); + if (0x81 <= $c && $c <= 0x9F || 0xE0 <= $c && $c <= 0xFC){ $i++ } + $i++,$len++; + } + $len; +} + +Ê +Benchmark: timing 100000 iterations of ab, ar, gr, le, sg, sj, wh, xs... + ab: 4 wallclock secs ( 3.46 usr + 0.00 sys = 3.46 CPU) @ 28901.73/s + ar: 6 wallclock secs ( 5.98 usr + 0.00 sys = 5.98 CPU) @ 16722.41/s + gr: 6 wallclock secs ( 5.50 usr + 0.00 sys = 5.50 CPU) @ 18181.82/s + le: 3 wallclock secs ( 2.09 usr + 0.00 sys = 2.09 CPU) @ 47846.89/s + sg: 2 wallclock secs ( 1.92 usr + 0.00 sys = 1.92 CPU) @ 52083.33/s + sj: 9 wallclock secs ( 8.57 usr + 0.00 sys = 8.57 CPU) @ 11668.61/s + wh: 5 wallclock secs ( 4.78 usr + 0.00 sys = 4.78 CPU) @ 20920.50/s + xs: 1 wallclock secs ( 0.38 usr + 0.00 sys = 0.38 CPU) @ 263157.89/s + (warning: too few iterations for a reliable count) + +XSUB +int +sjlength(arg) + SV* arg + PROTOTYPE: $ + PREINIT: + unsigned char *str, *p, *e; + STRLEN byte, len = 0; + CODE: + p = str = (unsigned char *)SvPV(arg, byte); + e = str + byte; + while (p < e) { + if (0x81 <= *p && *p <= 0x9F || 0xE0 <= *p && *p <= 0xFC) + ++p; + ++p, ++len; + } + RETVAL = len; + OUTPUT: + RETVAL + +¶PÊɪ¯é +Shift-JIS¶ñð¶PÊɪµÜµå€B±ÌêÍAXSðpµÄà Üè¬ÈèܹñŵœBÔèlÌXgðpÓ·éÌÉÔªæçêéÌ©AâÍèPerl̳K\»ÌÍ©È謢àÌŸÆ¢€±Æŵå€B +TvR[h +use Benchmark; + +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; +$s = "ú{êÆÎݺÞ\0ABC" x 100; + +timethese (1000, { + re => q{ + @re = $s =~ /$char/go; + }, + xs => q{ + @xs = sjsplit($s); + }, +}); + +Ê +Benchmark: timing 1000 iterations of re, xs... + re: 7 wallclock secs ( 6.65 usr + 0.00 sys = 6.65 CPU) @ 150.38/s + xs: 6 wallclock secs ( 5.33 usr + 0.00 sys = 5.33 CPU) @ 187.62/s + +XSUB +void +sjsplit(arg) + SV* arg + PROTOTYPE: $ + PREINIT: + unsigned char *str, *p, *e; + STRLEN ch, byte, len = 0; + PPCODE: + str = (unsigned char *)SvPV(arg,byte); + e = str + byte; + for (p = str; p < e; p++) { + if (0x81 <= *p && *p <= 0x9F || 0xE0 <= *p && *p <= 0xFC) ++p; + ++len; + } + EXTEND(SP,len); + for (p = str; p < e; p += ch) { + ch = (0x81 <= *p && *p <= 0x9F || 0xE0 < *p && *p <= 0xFC) ? 2 : 1; + PUSHs(sv_2mortal(newSVpv(p,ch))); + } + +FXȪ +¶ÅªÅÝœæ€ÉA¶ñðª·éÉÍAm//gªÖÅ·B +TvR[h +$onebyte = '[\x00-\x7F\xA1-\xDF]'; +$twobyte = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + +#PoCg¶ÌòÆQoCg¶Ìòɪ¯éB + while ($str =~ /\G($onebyte*)($twobyte*)/g) { + push @one, $1 if $1 ne ''; + push @two, $2 if $2 ne ''; + } + +#å_ªÅã̶ÆÈéæ€Éª·éB +# 'B' ÅÍ¢¢ªA¶ÉæÁÄÍÓªKvB + @sentences = $str =~ /\G$char*?(?:B|D|$)/g; + +ÁèÌ·³ÅØè»ëŠé +·¢¶ñðÁèÌ·³ioCg·jÅØè»ëŠéÈçAÌæ€ÉµÄÅ«Ü·B +TvR[h +$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + +$str = 'íŽíŽEUC-JPÉÏ·µÈ¢ÅAShift-JISÌÜÜ'. + 'Å«œç¢¢ñŸ¯ÇAÈ©È©Ê|ŸËŠB'; + +print join "\n", bytebreak($str,15); + +sub bytebreak{ + my($byte,$bmax,$ch,@lines); + my $str = shift; + $byte = $bmax = shift; + foreach $ch ($str =~ /$char/go) { + $byte += length $ch; # ̶ðp¬«µœ·³ + if ($byte <= $bmax) { + $lines[-1] .= $ch; # ··¬È¯êÎp¬«· + } else { + $byte = length $ch; + push @lines, $ch; # ³àȯêÎÌsÖ + } + } + return @lines; + # ·³ª«çÈ¢êÉAEðXy[XÅßœ¯êÎB + # return map {$_ .= ' ' x ($bmax - length)} @lines; +} + +Ö¥ÍAáŠÎÌæ€ÉµÄs¢Ü·BPÈlŠûÅÍAÖ¥ÍA(i) sªÖ¥¶ÌŒOÅüsµÈ¢G(ii) sÖ¥¶ÌŒãÅüsµÈ¢GÆ¢€±ÆÉÈèÜ·BÜœA"(a)"Ìæ€ÉAsÖ¥¶ÆsªÖ¥¶ÌÔÉP¶µ©È¢A±µœªÍA»ÌªÌS̪³üsÉÈé_Éàz¶µÜ·B +±ÌáÅͶñÌ·³ðoCg· length ÅKèµÄ¢Ü·ªA¶ÆoCgÍKžµàäáµÜ¹ñÌÅAêÉæÁÄÍiMVA¶ÍŒpɵœ¢Æ©AÜœÍv|[ViÌêÆ©AUTF-8ÌêÆ©j¶ðÔ· width Ìæ€ÈÖðè`·éKvª éŵå€B +ÜœA±ÌáÌâèûÅÍAÖ¥Éæé³üsªŸ¯Åêsæè·ÈéêÍAÍÝŸµðh°Ü¹ñB»êª¢éÈçAÖ¥ÌáOƵÄsðª¯éiáŠÎ$nextÌ·³ª$bmaxðŽŠÈ¢æ€É·éjuªKvŵå€B +TvR[h +$CharRE = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; + +# sªÖ¥¶iêªj +$NotAtBegin = q/)]}fhvxjnp!,.:;?ABXJKICDFGH/; +# sÖ¥¶iêªj +$NotAtEnd = q/([{eguwimo/; + +# nbV
ðìé +@NotAtBegin{$NotAtBegin =~ m/$CharRE/g} = (); +@NotAtEnd{ $NotAtEnd =~ m/$CharRE/g} = (); + +$Str = 'íŽíŽEUC-JPÉÏ·µÈ¢ÅAShift-JISÌÜÜ'. + 'Å«œç¢¢ñŸ¯ÇAÈ©È©Ê|ŸËŠB'; + +print join "\n", linebreak($Str,16); + +sub linebreak{ + my($byte,$i,@chars,$next,@lines); + my($str, $bmax, $pad) = @_; + + # $byteÍ̶ðp¬«µœÆ«Ì·³ + $byte = $bmax; # ·®üsÅ«éœßÌúlB + + # ¶PÊÉÎç· + @chars = $str =~ /$CharRE/go; + + for ($i=0; $i<@chars; $i++) { + $next .= $chars[$i]; # ̶ + $byte += length $chars[$i]; # ̶ðp¬«µœ·³ + + # ̶ªsÖ¥ÌÆ« + next if $i+1 < @chars && exists $NotAtEnd{ $chars[$i] }; + # ̶̪sªÖ¥ÌÆ« + next if $i+1 < @chars && exists $NotAtBegin{ $chars[$i+1] }; + + # sÌU誯 + # ··¬È¯êÎp¬«· + if ($byte <= $bmax) { + $lines[-1] .= $next; + } + # ³àȯêÎÌsÖ + else { + push @lines, $next; + $byte = length $next;# Vµ¢sÌ·³ + } + $next = ''; + } + return defined $pad && 1 == length $pad # lßš + ? map {$_ .= $pad x ($bmax - length)} @lines + : @lines; +} + +Ô纪èÖ¥Ìêi$bmin ©ç $bmaxÌÍÍð·jB + $bmin = $bmax - 2; # áŠÎB + + # sÌU誯 + # ··¬È¯êÎp¬«· + if ($byte <= $bmax && @lines && length $lines[-1] < $bmin){ + $lines[-1] .= $next; + } + # ³àȯêÎÌsÖ + else { + push @lines, $next; + $byte = length $next;# Vµ¢sÌ·³ + } + +ú{ê¶ñðÀÑÖŠé +ŒŒ¶ñðÜ\¹É\[g·éW
[ƵÄAShiftJIS/Collate.pm ª èÜ·BüèÆg¢ûÍPerlÌy[WÉßêΩ©èÜ·B +uÇÝE\LÆvÍÌæ€ÉµÄs¢Ü·BsortYomi\bhÌó¯æéXgÌevfÍA[ \Lñ, ÇÝñ ]Æ¢€zñt@XÅȯêÎÈèܹñB +TvR[h +use ShiftJIS::Collate; + +my @data = ( + [qw/ ¬R ±âÜ /], + [qw/ ·c Ȫœ /], + [qw/ c œÈ© /], + [qw/ éØ ·ž« /], + [qw/ ¬ ±¶Ü /], + [qw/ ±¶Ü /], + [qw/ ¬R šâÜ /], + [qw/ ¬ ±¶Ü /], + [qw/ ¬ ±¶Ü /], + [qw/ Rc âÜŸ /], + [qw/ ic Ȫœ /], +); + +@sort = ShiftJIS::Collate->new()->sortYomi(@data); + +uÈÕã\ÇÝÆvÍÌæ€ÉµÄs¢Ü·BsortDaihyo\bhÌó¯æéXgÌevfÍA[ \Lñ, ÇÝñ ]Æ¢€zñt@XÅȯêÎÈèܹñB +TvR[h + +#!perl +use ShiftJIS::Collate; + +my @data = ( + [qw/ ÉvZ çÞŸ¯¢³ñ /], + [qw/ JISÔ ¶·Îñ²€ /], + [qw/ ÀB Ÿ¿ /], + [qw/ À¡ ñÇ€ /], + [qw/ ÍŒ ©³¢ /], + [qw/ Íà ©í¿ /], + [qw/ pc ©œ /], + [qw/ pc ©Çœ /], + [qw/ @ «³ç¬ /], + [qw/ Íà ±€¿ /], + [qw/ KR ±€âÜ /], + [qw/ KR ³«âÜ /], + [qw/ ²¡ ³Æ€ /], + [qw/ ²ac ³íŸ /], + [qw/ ò ³íµÜ /], + [qw/ òc ³íŸ /], + [qw/ àVc ³íŸ /], + [qw/ pc ÂÌŸ /], + [qw/ Æä ¿¢ /], + [qw/ yä ¿¢ /], + [qw/ y ¿¢ /], + [qw/ Ëä Æ¢ /], + [qw/ Ëc ÆŸ /], + [qw/ yä Ç¢ /], + [qw/ y Ç¢ /], + [qw/ yò Æ« /], + [qw/ Àc â·Ÿ /], +); + +@sort = ShiftJIS::Collate->new()->sortDaihyo(@data); + + +Shift-JISÌ¿ðÜÞt@CŒ/pXŒ +{ÚÍAŒÌÚɵÄA¢s[ªÌÜÜLqµÄ¢Ü·ÌÅA൜©Qlɵæ€ÆvÁœêA\ªÉÓÌãA[ŸÅ«éÜŲ©ªÌìÆ«ÅeXgµÄŸ³¢B +Windows (95/98/NT/2000ÈÇ) ÅAt@CŒâpXŒª¿i±±ÅÍñoCg¶ÌÓ¡ÅgÁĢܷÌÅAœŒŒâLÈÇàÜÝÜ·BjðÜÞêAPerlŵ€ÛÉâ誶¶éÂ\«ª èÜ·B +öoCgª "\x5C" Ì¿ðàÂt@CŒ/pXŒ +fBNgìÖimkdir, rmdir, opendir, -d ÈÇjAt@CìÖiopen, unlink, -f ÈÇjÅAANZXÅ«È¢±Æª èÜ·B +t@CÌêÍAöÉŒpXy[XðYŠéÆANZXÅ«éêª èÜ·iáŠÎA-f '\ ' ÜœÍ -f "\x95\x5C\x20" ÈÇjB +fBNgÌêÍAöÉ / © \ ðYŠéÆANZXÅ«éêª èÜ·iáŠÎA-d '\/' ÜœÍ -d "\x95\x5C/" ÈÇjBöÉYŠé¶ðŒpXy[XƵÄàA€ÜANZXÅ«éêª èÜ·BYŠé¶ÌóâƵÄAOíÞ̶iXbV
A~LAójð°ÜµœªAÇ̶ªæ¢©ÍAÖÉæÁÄÙÈéêª éæ€Å·Bgp·éOÉ\ªÉeXgµÄŸ³¢B +ÈšAfBNgŒÌöÉ / © \ ðYŠéêAàÆàÆöÉ / © \ ªt¢Ä¢éêÉÍAñdÉt¯éÆ€Üs©È¢š»êª èÜ·ÌÅA¶ñAÌOÉžµœÙ€ªæ¢Åµå€B +Ç€µÄபsŸÅMÅ«È¢êÍA`` ÜœÍ qx// â system()ÖÈÇðʶÄWindowsÌR}hðÄÔ̪ǢÆv¢Ü·B +šÜ¯ + Shift-JIS Å©êœ POD ð Perl 5.8.1, 5.8.2 Ì Pod::Html Å HTML ÉÏ·µœêAAJ[ÌŒOÍA pÆŒŒ¶ [0xA6..0xDF] ð«A ŒÌeoCgͺüi'_'jÉÏ·³êéæ€Å·B ïÌIÉÍAuse locale; ºÅAlc Æ s/\W/_/g ðÀsµœÊ (cf. Pod::Html::anchorify) ÉÈèÜ·B +[2003-11-18] +PerlÌy[W diff --git a/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp new file mode 100644 index 0000000000..6d51f84fa1 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore> + +int main(int argc, char **argv) +{ + QCoreApplication a(argc, argv); + QTextStream qin(stdin); + if (!qin.atEnd()) { + int a, b, c; + qin >> a >> b >> c; + qDebug("%d %d %d", a, b, c); + } + return 0; +} diff --git a/tests/auto/corelib/io/qtextstream/stdinProcess/stdinProcess.pro b/tests/auto/corelib/io/qtextstream/stdinProcess/stdinProcess.pro new file mode 100644 index 0000000000..9cf4d19387 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/stdinProcess/stdinProcess.pro @@ -0,0 +1,7 @@ +SOURCES += main.cpp +QT = core +CONFIG += console +CONFIG -= app_bundle +DESTDIR = ./ + + diff --git a/tests/auto/corelib/io/qtextstream/task113817.txt b/tests/auto/corelib/io/qtextstream/task113817.txt new file mode 100644 index 0000000000..281ae8c9f2 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/task113817.txt @@ -0,0 +1,1095 @@ +1 13 -14
+2 13 14
+3 40 -3
+4 16383 4
+5 16383 5
+6 16383 6
+7 16383 7
+8 16383 8
+9 16383 9
+10 16383 10
+11 16383 -1
+12 16383 -1
+13 16383 -1
+14 16383 -1
+15 16383 -1
+16 16383 -1
+17 16383 -1
+18 16383 -1
+19 16383 -1
+20 16383 -1
+21 16383 -1
+22 16383 -1
+23 16383 -1
+24 16383 -1
+25 16383 -1
+26 16383 -1
+27 16383 -1
+28 16383 -1
+29 16383 -1
+30 16383 -1
+31 16383 -1
+32 16383 -1
+33 16383 -1
+34 16383 -1
+35 16383 -1
+36 16383 -1
+37 16383 -1
+38 16383 -1
+39 16383 -1
+40 16383 -1
+41 16383 -1
+42 16383 -1
+43 16383 -1
+44 16383 -1
+45 16383 -1
+46 16383 -1
+47 16383 -1
+48 16383 -1
+49 16383 -1
+50 16383 -1
+51 16383 -1
+52 16383 -1
+53 16383 -1
+54 16383 -1
+55 16383 -1
+56 16383 -1
+57 16383 -1
+58 16383 -1
+59 16383 -1
+60 16383 -1
+61 16383 -1
+62 16383 -1
+63 16383 -1
+64 16383 -1
+65 16383 -1
+66 16383 -1
+67 16383 -1
+68 16383 -1
+69 16383 -1
+70 16383 -1
+71 16383 -1
+72 16383 -1
+73 16383 -1
+74 16383 -1
+75 16383 -1
+76 16383 -1
+77 16383 -1
+78 16383 -1
+79 16383 -1
+80 16383 -1
+81 16383 -1
+82 16383 -1
+83 16383 -1
+84 16383 -1
+85 16383 -1
+86 16383 -1
+87 16383 -1
+88 16383 -1
+89 16383 -1
+90 16383 -1
+91 16383 -1
+92 16383 -1
+93 16383 -1
+94 16383 -1
+95 16383 -1
+96 16383 -1
+97 16383 -1
+98 16383 -1
+99 16383 -1
+100 16383 -1
+101 16383 -1
+102 16383 -1
+103 16383 -1
+104 16383 -1
+105 16383 -1
+106 16383 -1
+107 16383 -1
+108 16383 -1
+109 16383 -1
+110 16383 -1
+111 16383 -1
+112 16383 -1
+113 16383 -1
+114 16383 -1
+115 16383 -1
+116 16383 -1
+117 16383 -1
+118 16383 -1
+119 16383 -1
+120 16383 -1
+121 16383 -1
+122 16383 -1
+123 16383 -1
+124 16383 -1
+125 16383 -1
+126 16383 -1
+127 16383 -1
+128 16383 -1
+129 16383 -1
+130 16383 -1
+131 16383 -1
+132 16383 -1
+133 16383 -1
+134 16383 -1
+135 16383 -1
+136 16383 -1
+137 16383 -1
+138 16383 -1
+139 16383 -1
+140 16383 -1
+141 16383 -1
+142 16383 -1
+143 16383 -1
+144 16383 -1
+145 16383 -1
+146 16383 -1
+147 16383 -1
+148 16383 -1
+149 16383 -1
+150 16383 -1
+151 16383 -1
+152 16383 -1
+153 16383 -1
+154 16383 -1
+155 16383 -1
+156 16383 -1
+157 16383 -1
+158 16383 -1
+159 16383 -1
+160 16383 -1
+161 16383 -1
+162 16383 -1
+163 16383 -1
+164 16383 -1
+165 16383 -1
+166 16383 -1
+167 16383 -1
+168 16383 -1
+169 16383 -1
+170 16383 -1
+171 16383 -1
+172 16383 -1
+173 16383 -1
+174 16383 -1
+175 16383 -1
+176 16383 -1
+177 16383 -1
+178 16383 -1
+179 16383 -1
+180 16383 -1
+181 16383 -1
+182 16383 -1
+183 16383 -1
+184 16383 -1
+185 16383 -1
+186 16383 -1
+187 16383 -1
+188 16383 -1
+189 16383 -1
+190 16383 -1
+191 16383 -1
+192 16383 -1
+193 16383 -1
+194 16383 -1
+195 16383 -1
+196 16383 -1
+197 16383 -1
+198 16383 -1
+199 16383 -1
+200 16383 -1
+201 16383 -1
+202 16383 -1
+203 16383 -1
+204 16383 -1
+205 16383 -1
+206 16383 -1
+207 16383 -1
+208 16383 -1
+209 16383 -1
+210 16383 -1
+211 16383 -1
+212 16383 -1
+213 16383 -1
+214 16383 -1
+215 16383 -1
+216 16383 -1
+217 16383 -1
+218 16383 -1
+219 16383 -1
+220 16383 -1
+221 16383 -1
+222 16383 -1
+223 16383 -1
+224 16383 -1
+225 16383 -1
+226 16383 -1
+227 16383 -1
+228 16383 -1
+229 16383 -1
+230 16383 -1
+231 16383 -1
+232 16383 -1
+233 16383 -1
+234 16383 -1
+235 16383 -1
+236 16383 -1
+237 16383 -1
+238 16383 -1
+239 16383 -1
+240 16383 -1
+241 16383 -1
+242 16383 -1
+243 16383 -1
+244 16383 -1
+245 16383 -1
+246 16383 -1
+247 16383 -1
+248 16383 -1
+249 16383 -1
+250 16383 -1
+251 16383 -1
+252 16383 -1
+253 16383 -1
+254 16383 -1
+255 16383 -1
+256 16383 -1
+257 16383 -1
+258 16383 -1
+259 16383 -1
+260 16383 -1
+261 16383 -1
+262 16383 -1
+263 16383 -1
+264 16383 -1
+265 16383 -1
+266 16383 -1
+267 16383 -1
+268 16383 -1
+269 16383 -1
+270 16383 -1
+271 16383 -1
+272 16383 -1
+273 16383 -1
+274 16383 -1
+275 16383 -1
+276 16383 -1
+277 16383 -1
+278 16383 -1
+279 16383 -1
+280 16383 -1
+281 16383 -1
+282 16383 -1
+283 16383 -1
+284 16383 -1
+285 16383 -1
+286 16383 -1
+287 16383 -1
+288 16383 -1
+289 16383 -1
+290 16383 -1
+291 16383 -1
+292 16383 -1
+293 16383 -1
+294 16383 -1
+295 16383 -1
+296 16383 -1
+297 16383 -1
+298 16383 -1
+299 16383 -1
+300 16383 -1
+301 16383 -1
+302 16383 -1
+303 16383 -1
+304 16383 -1
+305 16383 -1
+306 16383 -1
+307 16383 -1
+308 16383 -1
+309 16383 -1
+310 16383 -1
+311 16383 -1
+312 16383 -1
+313 16383 -1
+314 16383 -1
+315 16383 -1
+316 16383 -1
+317 16383 -1
+318 16383 -1
+319 16383 -1
+320 16383 -1
+321 16383 -1
+322 16383 -1
+323 16383 -1
+324 16383 -1
+325 16383 -1
+326 16383 -1
+327 16383 -1
+328 16383 -1
+329 16383 -1
+330 16383 -1
+331 16383 -1
+332 16383 -1
+333 16383 -1
+334 16383 -1
+335 16383 -1
+336 16383 -1
+337 16383 -1
+338 16383 -1
+339 16383 -1
+340 16383 -1
+341 16383 -1
+342 16383 -1
+343 16383 -1
+344 16383 -1
+345 16383 -1
+346 16383 -1
+347 16383 -1
+348 16383 -1
+349 16383 -1
+350 16383 -1
+351 16383 -1
+352 16383 -1
+353 16383 -1
+354 16383 -1
+355 16383 -1
+356 16383 -1
+357 16383 -1
+358 16383 -1
+359 16383 -1
+360 16383 -1
+361 16383 -1
+362 16383 -1
+363 16383 -1
+364 16383 -1
+365 16383 -1
+366 16383 -1
+367 16383 -1
+368 16383 -1
+369 16383 -1
+370 16383 -1
+371 16383 -1
+372 16383 -1
+373 16383 -1
+374 16383 -1
+375 16383 -1
+376 16383 -1
+377 16383 -1
+378 16383 -1
+379 16383 -1
+380 16383 -1
+381 16383 -1
+382 16383 -1
+383 16383 -1
+384 16383 -1
+385 16383 -1
+386 16383 -1
+387 16383 -1
+388 16383 -1
+389 16383 -1
+390 16383 -1
+391 16383 -1
+392 16383 -1
+393 16383 -1
+394 16383 -1
+395 16383 -1
+396 16383 -1
+397 16383 -1
+398 16383 -1
+399 16383 -1
+400 16383 -1
+401 16383 -1
+402 16383 -1
+403 16383 -1
+404 16383 -1
+405 16383 -1
+406 16383 -1
+407 16383 -1
+408 16383 -1
+409 16383 -1
+410 16383 -1
+411 16383 -1
+412 16383 -1
+413 16383 -1
+414 16383 -1
+415 16383 -1
+416 16383 -1
+417 16383 -1
+418 16383 -1
+419 16383 -1
+420 16383 -1
+421 16383 -1
+422 16383 -1
+423 16383 -1
+424 16383 -1
+425 16383 -1
+426 16383 -1
+427 16383 -1
+428 16383 -1
+429 16383 -1
+430 16383 -1
+431 16383 -1
+432 16383 -1
+433 16383 -1
+434 16383 -1
+435 16383 -1
+436 16383 -1
+437 16383 -1
+438 16383 -1
+439 16383 -1
+440 16383 -1
+441 16383 -1
+442 16383 -1
+443 16383 -1
+444 16383 -1
+445 16383 -1
+446 16383 -1
+447 16383 -1
+448 16383 -1
+449 16383 -1
+450 16383 -1
+451 16383 -1
+452 16383 -1
+453 16383 -1
+454 16383 -1
+455 16383 -1
+456 16383 -1
+457 16383 -1
+458 16383 -1
+459 16383 -1
+460 16383 -1
+461 16383 -1
+462 16383 -1
+463 16383 -1
+464 16383 -1
+465 16383 -1
+466 16383 -1
+467 16383 -1
+468 16383 -1
+469 16383 -1
+470 16383 -1
+471 16383 -1
+472 16383 -1
+473 16383 -1
+474 16383 -1
+475 16383 -1
+476 16383 -1
+477 16383 -1
+478 16383 -1
+479 16383 -1
+480 16383 -1
+481 16383 -1
+482 16383 -1
+483 16383 -1
+484 16383 -1
+485 16383 -1
+486 16383 -1
+487 16383 -1
+488 16383 -1
+489 16383 -1
+490 16383 -1
+491 16383 -1
+492 16383 -1
+493 16383 -1
+494 16383 -1
+495 16383 -1
+496 16383 -1
+497 16383 -1
+498 16383 -1
+499 16383 -1
+500 16383 -1
+501 16383 -1
+502 16383 -1
+503 16383 -1
+504 16383 -1
+505 16383 -1
+506 16383 -1
+507 16383 -1
+508 16383 -1
+509 16383 -1
+510 16383 -1
+511 16383 -1
+512 16383 -1
+513 16383 -1
+514 16383 -1
+515 16383 -1
+516 16383 -1
+517 16383 -1
+518 16383 -1
+519 16383 -1
+520 16383 -1
+521 16383 -1
+522 16383 -1
+523 16383 -1
+524 16383 -1
+525 16383 -1
+526 16383 -1
+527 16383 -1
+528 16383 -1
+529 16383 -1
+530 16383 -1
+531 16383 -1
+532 16383 -1
+533 16383 -1
+534 16383 -1
+535 16383 -1
+536 16383 -1
+537 16383 -1
+538 16383 -1
+539 16383 -1
+540 16383 -1
+541 16383 -1
+542 16383 -1
+543 16383 -1
+544 16383 -1
+545 16383 -1
+546 16383 -1
+547 16383 -1
+548 16383 -1
+549 16383 -1
+550 16383 -1
+551 16383 -1
+552 16383 -1
+553 16383 -1
+554 16383 -1
+555 16383 -1
+556 16383 -1
+557 16383 -1
+558 16383 -1
+559 16383 -1
+560 16383 -1
+561 16383 -1
+562 16383 -1
+563 16383 -1
+564 16383 -1
+565 16383 -1
+566 16383 -1
+567 16383 -1
+568 16383 -1
+569 16383 -1
+570 16383 -1
+571 16383 -1
+572 16383 -1
+573 16383 -1
+574 16383 -1
+575 16383 -1
+576 16383 -1
+577 16383 -1
+578 16383 -1
+579 16383 -1
+580 16383 -1
+581 16383 -1
+582 16383 -1
+583 16383 -1
+584 16383 -1
+585 16383 -1
+586 16383 -1
+587 16383 -1
+588 16383 -1
+589 16383 -1
+590 16383 -1
+591 16383 -1
+592 16383 -1
+593 16383 -1
+594 16383 -1
+595 16383 -1
+596 16383 -1
+597 16383 -1
+598 16383 -1
+599 16383 -1
+600 16383 -1
+601 16383 -1
+602 16383 -1
+603 16383 -1
+604 16383 -1
+605 16383 -1
+606 16383 -1
+607 16383 -1
+608 16383 -1
+609 16383 -1
+610 16383 -1
+611 16383 -1
+612 16383 -1
+613 16383 -1
+614 16383 -1
+615 16383 -1
+616 16383 -1
+617 16383 -1
+618 16383 -1
+619 16383 -1
+620 16383 -1
+621 16383 -1
+622 16383 -1
+623 16383 -1
+624 16383 -1
+625 16383 -1
+626 16383 -1
+627 16383 -1
+628 16383 -1
+629 16383 -1
+630 16383 -1
+631 16383 -1
+632 16383 -1
+633 16383 -1
+634 16383 -1
+635 16383 -1
+636 16383 -1
+637 16383 -1
+638 16383 -1
+639 16383 -1
+640 16383 -1
+641 16383 -1
+642 16383 -1
+643 16383 -1
+644 16383 -1
+645 16383 -1
+646 16383 -1
+647 16383 -1
+648 16383 -1
+649 16383 -1
+650 16383 -1
+651 16383 -1
+652 16383 -1
+653 16383 -1
+654 16383 -1
+655 16383 -1
+656 16383 -1
+657 16383 -1
+658 16383 -1
+659 16383 -1
+660 16383 -1
+661 16383 -1
+662 16383 -1
+663 16383 -1
+664 16383 -1
+665 16383 -1
+666 16383 -1
+667 16383 -1
+668 16383 -1
+669 16383 -1
+670 16383 -1
+671 16383 -1
+672 16383 -1
+673 16383 -1
+674 16383 -1
+675 16383 -1
+676 16383 -1
+677 16383 -1
+678 16383 -1
+679 16383 -1
+680 16383 -1
+681 16383 -1
+682 16383 -1
+683 16383 -1
+684 16383 -1
+685 16383 -1
+686 16383 -1
+687 16383 -1
+688 16383 -1
+689 16383 -1
+690 16383 -1
+691 16383 -1
+692 16383 -1
+693 16383 -1
+694 16383 -1
+695 16383 -1
+696 16383 -1
+697 16383 -1
+698 16383 -1
+699 16383 -1
+700 16383 -1
+701 16383 -1
+702 16383 -1
+703 16383 -1
+704 16383 -1
+705 16383 -1
+706 16383 -1
+707 16383 -1
+708 16383 -1
+709 16383 -1
+710 16383 -1
+711 16383 -1
+712 16383 -1
+713 16383 -1
+714 16383 -1
+715 16383 -1
+716 16383 -1
+717 16383 -1
+718 16383 -1
+719 16383 -1
+720 16383 -1
+721 16383 -1
+722 16383 -1
+723 16383 -1
+724 16383 -1
+725 16383 -1
+726 16383 -1
+727 16383 -1
+728 16383 -1
+729 16383 -1
+730 16383 -1
+731 16383 -1
+732 16383 -1
+733 16383 -1
+734 16383 -1
+735 16383 -1
+736 16383 -1
+737 16383 -1
+738 16383 -1
+739 16383 -1
+740 16383 -1
+741 16383 -1
+742 16383 -1
+743 16383 -1
+744 16383 -1
+745 16383 -1
+746 16383 -1
+747 16383 -1
+748 16383 -1
+749 16383 -1
+750 16383 -1
+751 16383 -1
+752 16383 -1
+753 16383 -1
+754 16383 -1
+755 16383 -1
+756 16383 -1
+757 16383 -1
+758 16383 -1
+759 16383 -1
+760 16383 -1
+761 16383 -1
+762 16383 -1
+763 16383 -1
+764 16383 -1
+765 16383 -1
+766 16383 -1
+767 16383 -1
+768 16383 -1
+769 16383 -1
+770 16383 -1
+771 16383 -1
+772 16383 -1
+773 16383 -1
+774 16383 -1
+775 16383 -1
+776 16383 -1
+777 16383 -1
+778 16383 -1
+779 16383 -1
+780 16383 -1
+781 16383 -1
+782 16383 -1
+783 16383 -1
+784 16383 -1
+785 16383 -1
+786 16383 -1
+787 16383 -1
+788 16383 -1
+789 16383 -1
+790 16383 -1
+791 16383 -1
+792 16383 -1
+793 16383 -1
+794 16383 -1
+795 16383 -1
+796 16383 -1
+797 16383 -1
+798 16383 -1
+799 16383 -1
+800 16383 -1
+801 16383 -1
+802 16383 -1
+803 16383 -1
+804 16383 -1
+805 16383 -1
+806 16383 -1
+807 16383 -1
+808 16383 -1
+809 16383 -1
+810 16383 -1
+811 16383 -1
+812 16383 -1
+813 16383 -1
+814 16383 -1
+815 16383 -1
+816 16383 -1
+817 16383 -1
+818 16383 -1
+819 16383 -1
+820 16383 -1
+821 16383 -1
+822 16383 -1
+823 16383 -1
+824 16383 -1
+825 16383 -1
+826 16383 -1
+827 16383 -1
+828 16383 -1
+829 16383 -1
+830 16383 -1
+831 16383 -1
+832 16383 -1
+833 16383 -1
+834 16383 -1
+835 16383 -1
+836 16383 -1
+837 16383 -1
+838 16383 -1
+839 16383 -1
+840 16383 -1
+841 16383 -1
+842 16383 -1
+843 16383 -1
+844 16383 -1
+845 16383 -1
+846 16383 -1
+847 16383 -1
+848 16383 -1
+849 16383 -1
+850 16383 -1
+851 16383 -1
+852 16383 -1
+853 16383 -1
+854 16383 -1
+855 16383 -1
+856 16383 -1
+857 16383 -1
+858 16383 -1
+859 16383 -1
+860 16383 -1
+861 16383 -1
+862 16383 -1
+863 16383 -1
+864 16383 -1
+865 16383 -1
+866 16383 -1
+867 16383 -1
+868 16383 -1
+869 16383 -1
+870 16383 -1
+871 16383 -1
+872 16383 -1
+873 16383 -1
+874 16383 -1
+875 16383 -1
+876 16383 -1
+877 16383 -1
+878 16383 -1
+879 16383 -1
+880 16383 -1
+881 16383 -1
+882 16383 -1
+883 16383 -1
+884 16383 -1
+885 16383 -1
+886 16383 -1
+887 16383 -1
+888 16383 -1
+889 16383 -1
+890 16383 -1
+891 16383 -1
+892 16383 -1
+893 16383 -1
+894 16383 -1
+895 16383 -1
+896 16383 -1
+897 16383 -1
+898 16383 -1
+899 16383 -1
+900 16383 -1
+901 16383 -1
+902 16383 -1
+903 16383 -1
+904 16383 -1
+905 16383 -1
+906 16383 -1
+907 16383 -1
+908 16383 -1
+909 16383 -1
+910 16383 -1
+911 16383 -1
+912 16383 -1
+913 16383 -1
+914 16383 -1
+915 16383 -1
+916 16383 -1
+917 16383 -1
+918 16383 -1
+919 16383 -1
+920 16383 -1
+921 16383 -1
+922 16383 -1
+923 16383 -1
+924 16383 -1
+925 16383 -1
+926 16383 -1
+927 16383 -1
+928 16383 -1
+929 16383 -1
+930 16383 -1
+931 16383 -1
+932 16383 -1
+933 16383 -1
+934 16383 -1
+935 16383 -1
+936 16383 -1
+937 16383 -1
+938 16383 -1
+939 16383 -1
+940 16383 -1
+941 16383 -1
+942 16383 -1
+943 16383 -1
+944 16383 -1
+945 16383 -1
+946 16383 -1
+947 16383 -1
+948 16383 -1
+949 16383 -1
+950 16383 -1
+951 16383 -1
+952 16383 -1
+953 16383 -1
+954 16383 -1
+955 16383 -1
+956 16383 -1
+957 16383 -1
+958 16383 -1
+959 16383 -1
+960 16383 -1
+961 16383 -1
+962 16383 -1
+963 16383 -1
+964 16383 -1
+965 16383 -1
+966 16383 -1
+967 16383 -1
+968 16383 -1
+969 16383 -1
+970 16383 -1
+971 16383 -1
+972 16383 -1
+973 16383 -1
+974 16383 -1
+975 16383 -1
+976 16383 -1
+977 16383 -1
+978 16383 -1
+979 16383 -1
+980 16383 -1
+981 16383 -1
+982 16383 -1
+983 16383 -1
+984 16383 -1
+985 16383 -1
+986 16383 -1
+987 16383 -1
+988 16383 -1
+989 16383 -1
+990 16383 -1
+991 16383 -1
+992 16383 -1
+993 16383 -1
+994 16383 -1
+995 16383 -1
+996 16383 -1
+997 16383 -1
+998 16383 -1
+999 16383 -1
+1000 16383 -1
+1001 16383 -1
+1002 16383 -1
+1003 16383 -1
+1004 16383 -1
+1005 16383 -1
+1006 16383 -1
+1007 16383 -1
+1008 16383 -1
+1009 16383 -1
+1010 16383 -1
+1011 16383 -1
+1012 16383 -1
+1013 16383 -1
+1014 16383 -1
+1015 16383 -1
+1016 16383 -1
+1017 16383 -1
+1018 16383 -1
+1019 16383 -1
+1020 16383 -1
+1021 16383 -1
+1022 16383 -1
+1023 16383 -1
+1024 16383 -1
+1025 16383 -1
+1026 16383 -1
+1027 16383 -1
+1028 16383 -1
+1029 16383 -1
+1030 16383 -1
+1031 16383 -1
+1032 16383 -1
+1033 16383 -1
+1034 16383 -1
+1035 16383 -1
+1036 16383 -1
+1037 16383 -1
+1038 16383 -1
+1039 16383 -1
+1040 16383 -1
+1041 16383 -1
+1042 16383 -1
+1043 16383 -1
+1044 16383 -1
+1045 16383 -1
+1046 16383 -1
+1047 16383 -1
+1048 16383 -1
+1049 16383 -1
+1050 16383 -1
+1051 16383 -1
+1052 16383 -1
+1053 16383 -1
+1054 16383 -1
+1055 16383 -1
+1056 16383 -1
+1057 16383 -1
+1058 16383 -1
+1059 16383 -1
+1060 16383 -1
+1061 16383 -1
+1062 16383 -1
+1063 16383 -1
+1064 16383 -1
+1065 16383 -1
+1066 16383 -1
+1067 16383 -1
+1068 16383 -1
+1069 16383 -1
+1070 16383 -1
+1071 16383 -1
+1072 16383 -1
+1073 16383 -1
+1074 16383 -1
+1075 16383 -1
+1076 16383 -1
+1077 16383 -1
+1078 16383 -1
+1079 16383 -1
+1080 16383 -1
+1081 16383 -1
+1082 16383 -1
+1083 16383 -1
+1084 16383 -1
+1085 16383 -1
+1086 16383 -1
+1087 16383 -1
+1088 16383 -1
+1089 16383 -1
+1090 16383 -1
+1091 16383 -1
+1092 16383 -1
+1093 16383 -1
+1094 16383 -1
+1095 16383 -1
diff --git a/tests/auto/corelib/io/qtextstream/test/test.pro b/tests/auto/corelib/io/qtextstream/test/test.pro new file mode 100644 index 0000000000..e0eb4ef193 --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/test/test.pro @@ -0,0 +1,40 @@ +load(qttest_p4) +SOURCES += ../tst_qtextstream.cpp + +TARGET = ../tst_qtextstream + +win32 { + CONFIG(debug, debug|release) { + TARGET = ../../debug/tst_qtextstream +} else { + TARGET = ../../release/tst_qtextstream + } +} + +RESOURCES += ../qtextstream.qrc + +QT = core network + + +wince*|symbian: { + addFiles.files = ../rfc3261.txt ../shift-jis.txt ../task113817.txt ../qtextstream.qrc ../tst_qtextstream.cpp + addFiles.path = . + res.files = ../resources + res.path = . + DEPLOYMENT += addFiles +} + +wince*: { + DEFINES += SRCDIR=\\\"\\\" +}else:symbian { + # Symbian can't define SRCDIR meaningfully here + qt_not_deployed { + codecs_plugins.files = qcncodecs.dll qjpcodecs.dll qtwcodecs.dll qkrcodecs.dll + codecs_plugins.path = $$QT_PLUGINS_BASE_DIR/codecs + DEPLOYMENT += codecs_plugins + } +}else { + DEFINES += SRCDIR=\\\"$$PWD/../\\\" +} + + diff --git a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp new file mode 100644 index 0000000000..848f813d1e --- /dev/null +++ b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp @@ -0,0 +1,2919 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +/*-*-encoding:latin1-*-*/ +//#include <iostream> +//using namespace std; + +#include <QtTest/QtTest> + +#ifdef Q_OS_UNIX +#include <locale.h> +#endif + +#include <QBuffer> +#include <QByteArray> +#include <QCoreApplication> +#include <QDebug> +#include <QFile> +#include <QTcpSocket> +#include <QTextStream> +#include <QTextCodec> +#include <QProcess> + +#include "../../../network-settings.h" + +static const char *TestFileName = "testfile"; + +Q_DECLARE_METATYPE(qlonglong) +Q_DECLARE_METATYPE(qulonglong) +Q_DECLARE_METATYPE(QList<int>) + +QT_BEGIN_NAMESPACE +template<> struct QMetaTypeId<QIODevice::OpenModeFlag> +{ enum { Defined = 1 }; static inline int qt_metatype_id() { return QMetaType::Int; } }; +QT_END_NAMESPACE + +//TESTED_CLASS= +//TESTED_FILES= + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "" +#endif + +class tst_QTextStream : public QObject +{ + Q_OBJECT + +public: + tst_QTextStream(); + virtual ~tst_QTextStream(); + +public slots: + void init(); + void cleanup(); + +private slots: + void getSetCheck(); + void construction(); + + // lines + void readLineFromDevice_data(); + void readLineFromDevice(); + void readLineFromString_data(); + void readLineFromString(); + void readLineFromTextDevice_data(); + void readLineFromTextDevice(); + void readLineUntilNull(); + void readLineMaxlen_data(); + void readLineMaxlen(); + void readLinesFromBufferCRCR(); + + // all + void readAllFromDevice_data(); + void readAllFromDevice(); + void readAllFromString_data(); + void readAllFromString(); + void readLineFromStringThenChangeString(); + + // device tests + void setDevice(); + + // char operators + void QChar_operators_FromDevice_data(); + void QChar_operators_FromDevice(); + void char_operators_FromDevice_data(); + void char_operators_FromDevice(); + + // natural number read operator + void signedShort_read_operator_FromDevice_data(); + void signedShort_read_operator_FromDevice(); + void unsignedShort_read_operator_FromDevice_data(); + void unsignedShort_read_operator_FromDevice(); + void signedInt_read_operator_FromDevice_data(); + void signedInt_read_operator_FromDevice(); + void unsignedInt_read_operator_FromDevice_data(); + void unsignedInt_read_operator_FromDevice(); + void qlonglong_read_operator_FromDevice_data(); + void qlonglong_read_operator_FromDevice(); + void qulonglong_read_operator_FromDevice_data(); + void qulonglong_read_operator_FromDevice(); + + // natural number write operator + void signedShort_write_operator_ToDevice_data(); + void signedShort_write_operator_ToDevice(); + void unsignedShort_write_operator_ToDevice_data(); + void unsignedShort_write_operator_ToDevice(); + void signedInt_write_operator_ToDevice_data(); + void signedInt_write_operator_ToDevice(); + void unsignedInt_write_operator_ToDevice_data(); + void unsignedInt_write_operator_ToDevice(); + void qlonglong_write_operator_ToDevice_data(); + void qlonglong_write_operator_ToDevice(); + void qulonglong_write_operator_ToDevice_data(); + void qulonglong_write_operator_ToDevice(); + + void int_read_with_locale_data(); + void int_read_with_locale(); + + void int_write_with_locale_data(); + void int_write_with_locale(); + + // real number read operator + void float_read_operator_FromDevice_data(); + void float_read_operator_FromDevice(); + void double_read_operator_FromDevice_data(); + void double_read_operator_FromDevice(); + + // real number write operator + void float_write_operator_ToDevice_data(); + void float_write_operator_ToDevice(); + void double_write_operator_ToDevice_data(); + void double_write_operator_ToDevice(); + + void double_write_with_flags_data(); + void double_write_with_flags(); + + void double_write_with_precision_data(); + void double_write_with_precision(); + + // text read operators + void charPtr_read_operator_FromDevice_data(); + void charPtr_read_operator_FromDevice(); + void stringRef_read_operator_FromDevice_data(); + void stringRef_read_operator_FromDevice(); + void byteArray_read_operator_FromDevice_data(); + void byteArray_read_operator_FromDevice(); + + // text write operators + void string_write_operator_ToDevice_data(); + void string_write_operator_ToDevice(); + + // other + void skipWhiteSpace_data(); + void skipWhiteSpace(); + void lineCount_data(); + void lineCount(); + void performance(); + void hexTest_data(); + void hexTest(); + void binTest_data(); + void binTest(); + void octTest_data(); + void octTest(); + void zeroTermination(); + void ws_manipulator(); + void stillOpenWhenAtEnd(); + void readNewlines_data(); + void readNewlines(); + void seek(); + void pos(); + void pos2(); + void pos3LargeFile(); + void readStdin(); + void readAllFromStdin(); + void readLineFromStdin(); + void read(); + void qbool(); + void forcePoint(); + void forceSign(); + void read0d0d0a(); + void numeralCase_data(); + void numeralCase(); + void nanInf(); + void utf8IncompleteAtBufferBoundary_data(); + void utf8IncompleteAtBufferBoundary(); + void writeSeekWriteNoBOM(); + + // status + void status_real_read_data(); + void status_real_read(); + void status_integer_read(); + void status_word_read(); + void status_write_error(); + + // use case tests + void useCase1(); + void useCase2(); + + // manipulators + void manipulators_data(); + void manipulators(); + + // UTF-16 BOM (Byte Order Mark) + void generateBOM(); + void readBomSeekBackReadBomAgain(); + + // task-specific tests + void task180679_alignAccountingStyle(); + void task178772_setCodec(); + +private: + void generateLineData(bool for_QString); + void generateAllData(bool for_QString); + void generateOperatorCharData(bool for_QString); + void generateNaturalNumbersData(bool for_QString); + void generateRealNumbersData(bool for_QString); + void generateStringData(bool for_QString); + void generateRealNumbersDataWrite(); +}; + +// Testing get/set functions +void tst_QTextStream::getSetCheck() +{ + // Initialize codecs + int argc = 0; + char **argv = 0; + QCoreApplication app(argc, argv); + + QTextStream obj1; + // QTextCodec * QTextStream::codec() + // void QTextStream::setCodec(QTextCodec *) + QTextCodec *var1 = QTextCodec::codecForName("en"); + obj1.setCodec(var1); + QCOMPARE(var1, obj1.codec()); + obj1.setCodec((QTextCodec *)0); + QCOMPARE((QTextCodec *)0, obj1.codec()); + + // bool QTextStream::autoDetectUnicode() + // void QTextStream::setAutoDetectUnicode(bool) + obj1.setAutoDetectUnicode(false); + QCOMPARE(false, obj1.autoDetectUnicode()); + obj1.setAutoDetectUnicode(true); + QCOMPARE(true, obj1.autoDetectUnicode()); + + // bool QTextStream::generateByteOrderMark() + // void QTextStream::setGenerateByteOrderMark(bool) + obj1.setGenerateByteOrderMark(false); + QCOMPARE(false, obj1.generateByteOrderMark()); + obj1.setGenerateByteOrderMark(true); + QCOMPARE(true, obj1.generateByteOrderMark()); + + // QIODevice * QTextStream::device() + // void QTextStream::setDevice(QIODevice *) + QFile *var4 = new QFile; + obj1.setDevice(var4); + QCOMPARE(static_cast<QIODevice *>(var4), obj1.device()); + obj1.setDevice((QIODevice *)0); + QCOMPARE((QIODevice *)0, obj1.device()); + delete var4; + + // Status QTextStream::status() + // void QTextStream::setStatus(Status) + obj1.setStatus(QTextStream::Status(QTextStream::Ok)); + QCOMPARE(QTextStream::Status(QTextStream::Ok), obj1.status()); + obj1.setStatus(QTextStream::Status(QTextStream::ReadPastEnd)); + QCOMPARE(QTextStream::Status(QTextStream::ReadPastEnd), obj1.status()); + obj1.resetStatus(); + obj1.setStatus(QTextStream::Status(QTextStream::ReadCorruptData)); + QCOMPARE(QTextStream::Status(QTextStream::ReadCorruptData), obj1.status()); + + // FieldAlignment QTextStream::fieldAlignment() + // void QTextStream::setFieldAlignment(FieldAlignment) + obj1.setFieldAlignment(QTextStream::FieldAlignment(QTextStream::AlignLeft)); + QCOMPARE(QTextStream::FieldAlignment(QTextStream::AlignLeft), obj1.fieldAlignment()); + obj1.setFieldAlignment(QTextStream::FieldAlignment(QTextStream::AlignRight)); + QCOMPARE(QTextStream::FieldAlignment(QTextStream::AlignRight), obj1.fieldAlignment()); + obj1.setFieldAlignment(QTextStream::FieldAlignment(QTextStream::AlignCenter)); + QCOMPARE(QTextStream::FieldAlignment(QTextStream::AlignCenter), obj1.fieldAlignment()); + obj1.setFieldAlignment(QTextStream::FieldAlignment(QTextStream::AlignAccountingStyle)); + QCOMPARE(QTextStream::FieldAlignment(QTextStream::AlignAccountingStyle), obj1.fieldAlignment()); + + // QChar QTextStream::padChar() + // void QTextStream::setPadChar(QChar) + QChar var7 = 'Q'; + obj1.setPadChar(var7); + QCOMPARE(var7, obj1.padChar()); + obj1.setPadChar(QChar()); + QCOMPARE(QChar(), obj1.padChar()); + + // int QTextStream::fieldWidth() + // void QTextStream::setFieldWidth(int) + obj1.setFieldWidth(0); + QCOMPARE(0, obj1.fieldWidth()); + obj1.setFieldWidth(INT_MIN); + QCOMPARE(INT_MIN, obj1.fieldWidth()); + obj1.setFieldWidth(INT_MAX); + QCOMPARE(INT_MAX, obj1.fieldWidth()); + + // NumberFlags QTextStream::numberFlags() + // void QTextStream::setNumberFlags(NumberFlags) + obj1.setNumberFlags(QTextStream::NumberFlags(QTextStream::ShowBase)); + QCOMPARE(QTextStream::NumberFlags(QTextStream::ShowBase), obj1.numberFlags()); + obj1.setNumberFlags(QTextStream::NumberFlags(QTextStream::ForcePoint)); + QCOMPARE(QTextStream::NumberFlags(QTextStream::ForcePoint), obj1.numberFlags()); + obj1.setNumberFlags(QTextStream::NumberFlags(QTextStream::ForceSign)); + QCOMPARE(QTextStream::NumberFlags(QTextStream::ForceSign), obj1.numberFlags()); + obj1.setNumberFlags(QTextStream::NumberFlags(QTextStream::UppercaseBase)); + QCOMPARE(QTextStream::NumberFlags(QTextStream::UppercaseBase), obj1.numberFlags()); + obj1.setNumberFlags(QTextStream::NumberFlags(QTextStream::UppercaseDigits)); + QCOMPARE(QTextStream::NumberFlags(QTextStream::UppercaseDigits), obj1.numberFlags()); + + // int QTextStream::integerBase() + // void QTextStream::setIntegerBase(int) + obj1.setIntegerBase(0); + QCOMPARE(0, obj1.integerBase()); + obj1.setIntegerBase(INT_MIN); + QCOMPARE(INT_MIN, obj1.integerBase()); + obj1.setIntegerBase(INT_MAX); + QCOMPARE(INT_MAX, obj1.integerBase()); + + // RealNumberNotation QTextStream::realNumberNotation() + // void QTextStream::setRealNumberNotation(RealNumberNotation) + obj1.setRealNumberNotation(QTextStream::RealNumberNotation(QTextStream::SmartNotation)); + QCOMPARE(QTextStream::RealNumberNotation(QTextStream::SmartNotation), obj1.realNumberNotation()); + obj1.setRealNumberNotation(QTextStream::RealNumberNotation(QTextStream::FixedNotation)); + QCOMPARE(QTextStream::RealNumberNotation(QTextStream::FixedNotation), obj1.realNumberNotation()); + obj1.setRealNumberNotation(QTextStream::RealNumberNotation(QTextStream::ScientificNotation)); + QCOMPARE(QTextStream::RealNumberNotation(QTextStream::ScientificNotation), obj1.realNumberNotation()); + + // int QTextStream::realNumberPrecision() + // void QTextStream::setRealNumberPrecision(int) + obj1.setRealNumberPrecision(0); + QCOMPARE(0, obj1.realNumberPrecision()); + obj1.setRealNumberPrecision(INT_MIN); + QCOMPARE(6, obj1.realNumberPrecision()); // Setting a negative precision reverts it to the default value (6). + obj1.setRealNumberPrecision(INT_MAX); + QCOMPARE(INT_MAX, obj1.realNumberPrecision()); +} + +tst_QTextStream::tst_QTextStream() +{ + Q_SET_DEFAULT_IAP +} + +tst_QTextStream::~tst_QTextStream() +{ +} + +void tst_QTextStream::init() +{ +} + +void tst_QTextStream::cleanup() +{ + QCoreApplication::instance()->processEvents(); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::construction() +{ + QTextStream stream; + QCOMPARE(stream.codec(), QTextCodec::codecForLocale()); + QCOMPARE(stream.device(), static_cast<QIODevice *>(0)); + QCOMPARE(stream.string(), static_cast<QString *>(0)); + + QTest::ignoreMessage(QtWarningMsg, "QTextStream: No device"); + QVERIFY(stream.atEnd()); + + QTest::ignoreMessage(QtWarningMsg, "QTextStream: No device"); + QCOMPARE(stream.readAll(), QString()); + +} + +void tst_QTextStream::generateLineData(bool for_QString) +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<QStringList>("lines"); + + // latin-1 + QTest::newRow("emptyer") << QByteArray() << QStringList(); + QTest::newRow("lf") << QByteArray("\n") << (QStringList() << ""); + QTest::newRow("crlf") << QByteArray("\r\n") << (QStringList() << ""); + QTest::newRow("oneline/nothing") << QByteArray("ole") << (QStringList() << "ole"); + QTest::newRow("oneline/lf") << QByteArray("ole\n") << (QStringList() << "ole"); + QTest::newRow("oneline/crlf") << QByteArray("ole\r\n") << (QStringList() << "ole"); + QTest::newRow("twolines/lf/lf") << QByteArray("ole\ndole\n") << (QStringList() << "ole" << "dole"); + QTest::newRow("twolines/crlf/crlf") << QByteArray("ole\r\ndole\r\n") << (QStringList() << "ole" << "dole"); + QTest::newRow("twolines/lf/crlf") << QByteArray("ole\ndole\r\n") << (QStringList() << "ole" << "dole"); + QTest::newRow("twolines/lf/nothing") << QByteArray("ole\ndole") << (QStringList() << "ole" << "dole"); + QTest::newRow("twolines/crlf/nothing") << QByteArray("ole\r\ndole") << (QStringList() << "ole" << "dole"); + QTest::newRow("threelines/lf/lf/lf") << QByteArray("ole\ndole\ndoffen\n") << (QStringList() << "ole" << "dole" << "doffen"); + QTest::newRow("threelines/crlf/crlf/crlf") << QByteArray("ole\r\ndole\r\ndoffen\r\n") << (QStringList() << "ole" << "dole" << "doffen"); + QTest::newRow("threelines/crlf/crlf/nothing") << QByteArray("ole\r\ndole\r\ndoffen") << (QStringList() << "ole" << "dole" << "doffen"); + + if (!for_QString) { + // utf-8 + QTest::newRow("utf8/twolines") + << QByteArray("\xef\xbb\xbf" + "\x66\x67\x65\x0a" + "\x66\x67\x65\x0a", 11) + << (QStringList() << "fge" << "fge"); + + // utf-16 + // one line + QTest::newRow("utf16-BE/nothing") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65", 8) << (QStringList() << "\345ge"); + QTest::newRow("utf16-LE/nothing") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00", 8) << (QStringList() << "\345ge"); + QTest::newRow("utf16-BE/lf") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65\x00\x0a", 10) << (QStringList() << "\345ge"); + QTest::newRow("utf16-LE/lf") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00\x0a\x00", 10) << (QStringList() << "\345ge"); + + // two lines + QTest::newRow("utf16-BE/twolines") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65\x00\x0a" + "\x00\xe5\x00\x67\x00\x65\x00\x0a", 18) + << (QStringList() << "\345ge" << "\345ge"); + QTest::newRow("utf16-LE/twolines") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00\x0a\x00" + "\xe5\x00\x67\x00\x65\x00\x0a\x00", 18) + << (QStringList() << "\345ge" << "\345ge"); + + // three lines + QTest::newRow("utf16-BE/threelines") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65\x00\x0a" + "\x00\xe5\x00\x67\x00\x65\x00\x0a" + "\x00\xe5\x00\x67\x00\x65\x00\x0a", 26) + << (QStringList() << "\345ge" << "\345ge" << "\345ge"); + QTest::newRow("utf16-LE/threelines") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00\x0a\x00" + "\xe5\x00\x67\x00\x65\x00\x0a\x00" + "\xe5\x00\x67\x00\x65\x00\x0a\x00", 26) + << (QStringList() << "\345ge" << "\345ge" << "\345ge"); + + // utf-32 + QTest::newRow("utf32-BE/twolines") + << QByteArray("\x00\x00\xfe\xff" + "\x00\x00\x00\xe5\x00\x00\x00\x67\x00\x00\x00\x65\x00\x00\x00\x0a" + "\x00\x00\x00\xe5\x00\x00\x00\x67\x00\x00\x00\x65\x00\x00\x00\x0a", 36) + << (QStringList() << "\345ge" << "\345ge"); + QTest::newRow("utf32-LE/twolines") + << QByteArray("\xff\xfe\x00\x00" + "\xe5\x00\x00\x00\x67\x00\x00\x00\x65\x00\x00\x00\x0a\x00\x00\x00" + "\xe5\x00\x00\x00\x67\x00\x00\x00\x65\x00\x00\x00\x0a\x00\x00\x00", 36) + << (QStringList() << "\345ge" << "\345ge"); + } + + // partials + QTest::newRow("cr") << QByteArray("\r") << (QStringList() << ""); + QTest::newRow("oneline/cr") << QByteArray("ole\r") << (QStringList() << "ole"); + if (!for_QString) + QTest::newRow("utf16-BE/cr") << QByteArray("\xfe\xff\x00\xe5\x00\x67\x00\x65\x00\x0d", 10) << (QStringList() << "\345ge"); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromDevice_data() +{ + generateLineData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromDevice() +{ + QFETCH(QByteArray, data); + QFETCH(QStringList, lines); + + QFile::remove(TestFileName); + QFile file(TestFileName); + QVERIFY(file.open(QFile::ReadWrite)); + QCOMPARE(file.write(data), qlonglong(data.size())); + QVERIFY(file.flush()); + file.seek(0); + + QTextStream stream(&file); + QStringList list; + while (!stream.atEnd()) + list << stream.readLine(); + + QCOMPARE(list, lines); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineMaxlen_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QStringList>("lines"); + + QTest::newRow("Hey") + << QString("Hey") + << (QStringList() << QString("Hey") << QString("")); + QTest::newRow("Hey\\n") + << QString("Hey\n") + << (QStringList() << QString("Hey") << QString("")); + QTest::newRow("HelloWorld") + << QString("HelloWorld") + << (QStringList() << QString("Hello") << QString("World")); + QTest::newRow("Helo\\nWorlds") + << QString("Helo\nWorlds") + << (QStringList() << QString("Helo") << QString("World")); + QTest::newRow("AAAAA etc.") + << QString(16385, QLatin1Char('A')) + << (QStringList() << QString("AAAAA") << QString("AAAAA")); + QTest::newRow("multibyte string") + << QString::fromUtf8("\341\233\222\341\233\226\341\232\251\341\232\271\341\232\242\341\233\232\341\232\240\n") + << (QStringList() << QString::fromUtf8("\341\233\222\341\233\226\341\232\251\341\232\271\341\232\242") + << QString::fromUtf8("\341\233\232\341\232\240")); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineMaxlen() +{ + QFETCH(QString, input); + QFETCH(QStringList, lines); + for (int i = 0; i < 2; ++i) { + bool useDevice = (i == 1); + QTextStream stream; + QFile::remove("testfile"); + QFile file("testfile"); + if (useDevice) { + file.open(QIODevice::ReadWrite); + file.write(input.toUtf8()); + file.seek(0); + stream.setDevice(&file); + stream.setCodec("utf-8"); + } else { + stream.setString(&input); + } + + QStringList list; + list << stream.readLine(5); + list << stream.readLine(5); + + QCOMPARE(list, lines); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLinesFromBufferCRCR() +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QByteArray data("0123456789\r\r\n"); + + for (int i = 0; i < 10000; ++i) + buffer.write(data); + + buffer.close(); + if (buffer.open(QIODevice::ReadOnly|QIODevice::Text)) { + QTextStream stream(&buffer); + while (!stream.atEnd()) + QCOMPARE(stream.readLine(), QString("0123456789")); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromString_data() +{ + generateLineData(true); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromString() +{ + QFETCH(QByteArray, data); + QFETCH(QStringList, lines); + + QString dataString = data; + + QTextStream stream(&dataString, QIODevice::ReadOnly); + QStringList list; + while (!stream.atEnd()) + list << stream.readLine(); + + QCOMPARE(list, lines); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromStringThenChangeString() +{ + QString first = "First string"; + QString second = "Second string"; + + QTextStream stream(&first, QIODevice::ReadOnly); + QString result = stream.readLine(); + QCOMPARE(first, result); + + stream.setString(&second, QIODevice::ReadOnly); + result = stream.readLine(); + QCOMPARE(second, result); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::setDevice() +{ + // Check that the read buffer is reset after setting a new device + QByteArray data1("Hello World"); + QByteArray data2("How are you"); + + QBuffer bufferOld(&data1); + bufferOld.open(QIODevice::ReadOnly); + + QBuffer bufferNew(&data2); + bufferNew.open(QIODevice::ReadOnly); + + QString text; + QTextStream stream(&bufferOld); + stream >> text; + QCOMPARE(text, QString("Hello")); + + stream.setDevice(&bufferNew); + stream >> text; + QCOMPARE(text, QString("How")); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromTextDevice_data() +{ + generateLineData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromTextDevice() +{ + QFETCH(QByteArray, data); + QFETCH(QStringList, lines); + + for (int i = 0; i < 8; ++i) { + QBuffer buffer(&data); + if (i < 4) + QVERIFY(buffer.open(QIODevice::ReadOnly | QIODevice::Text)); + else + QVERIFY(buffer.open(QIODevice::ReadOnly)); + + QTextStream stream(&buffer); + QStringList list; + while (!stream.atEnd()) { + stream.pos(); // <- triggers side effects + QString line; + + if (i & 1) { + QChar c; + while (!stream.atEnd()) { + stream >> c; + if (stream.status() == QTextStream::Ok) { + if (c != QLatin1Char('\n') && c != QLatin1Char('\r')) + line += c; + if (c == QLatin1Char('\n')) + break; + } + } + } else { + line = stream.readLine(); + } + + if ((i & 3) == 3 && !QString(QTest::currentDataTag()).contains("utf16")) + stream.seek(stream.pos()); + list << line; + } + QCOMPARE(list, lines); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::generateAllData(bool for_QString) +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<QString>("output"); + + // latin-1 + QTest::newRow("empty") << QByteArray() << QString(); + QTest::newRow("latin1-a") << QByteArray("a") << QString("a"); + QTest::newRow("latin1-a\\r") << QByteArray("a\r") << QString("a\r"); + QTest::newRow("latin1-a\\r\\n") << QByteArray("a\r\n") << QString("a\r\n"); + QTest::newRow("latin1-a\\n") << QByteArray("a\n") << QString("a\n"); + + // utf-16 + if (!for_QString) { + // one line + QTest::newRow("utf16-BE/nothing") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65", 8) << QString("\345ge"); + QTest::newRow("utf16-LE/nothing") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00", 8) << QString("\345ge"); + QTest::newRow("utf16-BE/lf") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65\x00\x0a", 10) << QString("\345ge\n"); + QTest::newRow("utf16-LE/lf") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00\x0a\x00", 10) << QString("\345ge\n"); + QTest::newRow("utf16-BE/crlf") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65\x00\x0d\x00\x0a", 12) << QString("\345ge\r\n"); + QTest::newRow("utf16-LE/crlf") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00\x0d\x00\x0a\x00", 12) << QString("\345ge\r\n"); + + // two lines + QTest::newRow("utf16-BE/twolines") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65\x00\x0a" + "\x00\xe5\x00\x67\x00\x65\x00\x0a", 18) + << QString("\345ge\n\345ge\n"); + QTest::newRow("utf16-LE/twolines") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00\x0a\x00" + "\xe5\x00\x67\x00\x65\x00\x0a\x00", 18) + << QString("\345ge\n\345ge\n"); + + // three lines + QTest::newRow("utf16-BE/threelines") + << QByteArray("\xfe\xff" + "\x00\xe5\x00\x67\x00\x65\x00\x0a" + "\x00\xe5\x00\x67\x00\x65\x00\x0a" + "\x00\xe5\x00\x67\x00\x65\x00\x0a", 26) + << QString("\345ge\n\345ge\n\345ge\n"); + QTest::newRow("utf16-LE/threelines") + << QByteArray("\xff\xfe" + "\xe5\x00\x67\x00\x65\x00\x0a\x00" + "\xe5\x00\x67\x00\x65\x00\x0a\x00" + "\xe5\x00\x67\x00\x65\x00\x0a\x00", 26) + << QString("\345ge\n\345ge\n\345ge\n"); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineUntilNull() +{ + QFile file(SRCDIR "rfc3261.txt"); + QVERIFY(file.open(QFile::ReadOnly)); + + QTextStream stream(&file); + for (int i = 0; i < 15066; ++i) { + QString line = stream.readLine(); + QVERIFY(!line.isNull()); + QVERIFY(!line.isNull()); + } + QVERIFY(!stream.readLine().isNull()); + QVERIFY(stream.readLine().isNull()); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readAllFromDevice_data() +{ + generateAllData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readAllFromDevice() +{ + QFETCH(QByteArray, input); + QFETCH(QString, output); + + QBuffer buffer(&input); + buffer.open(QBuffer::ReadOnly); + + QTextStream stream(&buffer); + QCOMPARE(stream.readAll(), output); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readAllFromString_data() +{ + generateAllData(true); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readAllFromString() +{ + QFETCH(QByteArray, input); + QFETCH(QString, output); + + QString str = input; + + QTextStream stream(&str); + QCOMPARE(stream.readAll(), output); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::skipWhiteSpace_data() +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<QChar>("output"); + + // latin1 + QTest::newRow("empty") << QByteArray() << QChar('\0'); + QTest::newRow(" one") << QByteArray(" one") << QChar('o'); + QTest::newRow("\\none") << QByteArray("\none") << QChar('o'); + QTest::newRow("\\n one") << QByteArray("\n one") << QChar('o'); + QTest::newRow(" \\r\\n one") << QByteArray(" \r\n one") << QChar('o'); + + // utf-16 + QTest::newRow("utf16-BE (empty)") << QByteArray("\xfe\xff", 2) << QChar('\0'); + QTest::newRow("utf16-BE ( one)") << QByteArray("\xfe\xff\x00 \x00o\x00n\x00e", 10) << QChar('o'); + QTest::newRow("utf16-BE (\\none)") << QByteArray("\xfe\xff\x00\n\x00o\x00n\x00e", 10) << QChar('o'); + QTest::newRow("utf16-BE (\\n one)") << QByteArray("\xfe\xff\x00\n\x00 \x00o\x00n\x00e", 12) << QChar('o'); + QTest::newRow("utf16-BE ( \\r\\n one)") << QByteArray("\xfe\xff\x00 \x00\r\x00\n\x00 \x00o\x00n\x00e", 20) << QChar('o'); + + QTest::newRow("utf16-LE (empty)") << QByteArray("\xff\xfe", 2) << QChar('\0'); + QTest::newRow("utf16-LE ( one)") << QByteArray("\xff\xfe \x00o\x00n\x00e\x00", 10) << QChar('o'); + QTest::newRow("utf16-LE (\\none)") << QByteArray("\xff\xfe\n\x00o\x00n\x00e\x00", 10) << QChar('o'); + QTest::newRow("utf16-LE (\\n one)") << QByteArray("\xff\xfe\n\x00 \x00o\x00n\x00e\x00", 12) << QChar('o'); + QTest::newRow("utf16-LE ( \\r\\n one)") << QByteArray("\xff\xfe \x00\r\x00\n\x00 \x00o\x00n\x00e\x00", 20) << QChar('o'); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::skipWhiteSpace() +{ + QFETCH(QByteArray, input); + QFETCH(QChar, output); + + QBuffer buffer(&input); + buffer.open(QBuffer::ReadOnly); + + QTextStream stream(&buffer); + stream.skipWhiteSpace(); + + QChar tmp; + stream >> tmp; + + QCOMPARE(tmp, output); + + QString str = input; + QTextStream stream2(&input); + stream2.skipWhiteSpace(); + + stream2 >> tmp; + + QCOMPARE(tmp, output); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::lineCount_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<int>("lineCount"); + + QTest::newRow("empty") << QByteArray() << 0; + QTest::newRow("oneline") << QByteArray("a\n") << 1; + QTest::newRow("twolines") << QByteArray("a\nb\n") << 2; + QTest::newRow("oneemptyline") << QByteArray("\n") << 1; + QTest::newRow("twoemptylines") << QByteArray("\n\n") << 2; + QTest::newRow("buffersize-1 line") << QByteArray(16382, '\n') << 16382; + QTest::newRow("buffersize line") << QByteArray(16383, '\n') << 16383; + QTest::newRow("buffersize+1 line") << QByteArray(16384, '\n') << 16384; + QTest::newRow("buffersize+2 line") << QByteArray(16385, '\n') << 16385; + + QFile file(SRCDIR "rfc3261.txt"); file.open(QFile::ReadOnly); + QTest::newRow("rfc3261") << file.readAll() << 15067; +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::lineCount() +{ + QFETCH(QByteArray, data); + QFETCH(int, lineCount); + + QFile out("out.txt"); + out.open(QFile::WriteOnly); + + QTextStream lineReader(data); + int lines = 0; + while (!lineReader.atEnd()) { + QString line = lineReader.readLine(); + out.write(line.toLatin1() + "\n"); + ++lines; + } + + out.close(); + QCOMPARE(lines, lineCount); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::performance() +{ + // Phase #1 - test speed of reading a huge text file with QFile. + QTime stopWatch; + + int elapsed1 = 0; + int elapsed2 = 0; + + stopWatch.restart(); + int nlines1 = 0; + QFile file(SRCDIR "rfc3261.txt"); + QVERIFY(file.open(QFile::ReadOnly)); + + while (!file.atEnd()) { + ++nlines1; + file.readLine(); + } + + elapsed1 += stopWatch.elapsed(); + stopWatch.restart(); + + int nlines2 = 0; + QFile file2(SRCDIR "rfc3261.txt"); + QVERIFY(file2.open(QFile::ReadOnly)); + + QTextStream stream(&file2); + while (!stream.atEnd()) { + ++nlines2; + stream.readLine(); + } + + elapsed2 += stopWatch.elapsed(); + QCOMPARE(nlines1, nlines2); + + qDebug("QFile used %.2f seconds to read the file", + elapsed1 / 1000.0); + + qDebug("QTextStream used %.2f seconds to read the file", + elapsed2 / 1000.0); + if (elapsed2 > elapsed1) { + qDebug("QFile is %.2fx faster than QTextStream", + double(elapsed2) / double(elapsed1)); + } else { + qDebug("QTextStream is %.2fx faster than QFile", + double(elapsed1) / double(elapsed2)); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::hexTest_data() +{ + QTest::addColumn<qlonglong>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << Q_INT64_C(0) << QByteArray("0x0"); + QTest::newRow("1") << Q_INT64_C(1) << QByteArray("0x1"); + QTest::newRow("2") << Q_INT64_C(2) << QByteArray("0x2"); + QTest::newRow("3") << Q_INT64_C(3) << QByteArray("0x3"); + QTest::newRow("4") << Q_INT64_C(4) << QByteArray("0x4"); + QTest::newRow("5") << Q_INT64_C(5) << QByteArray("0x5"); + QTest::newRow("6") << Q_INT64_C(6) << QByteArray("0x6"); + QTest::newRow("7") << Q_INT64_C(7) << QByteArray("0x7"); + QTest::newRow("8") << Q_INT64_C(8) << QByteArray("0x8"); + QTest::newRow("9") << Q_INT64_C(9) << QByteArray("0x9"); + QTest::newRow("a") << Q_INT64_C(0xa) << QByteArray("0xa"); + QTest::newRow("b") << Q_INT64_C(0xb) << QByteArray("0xb"); + QTest::newRow("c") << Q_INT64_C(0xc) << QByteArray("0xc"); + QTest::newRow("d") << Q_INT64_C(0xd) << QByteArray("0xd"); + QTest::newRow("e") << Q_INT64_C(0xe) << QByteArray("0xe"); + QTest::newRow("f") << Q_INT64_C(0xf) << QByteArray("0xf"); + QTest::newRow("-1") << Q_INT64_C(-1) << QByteArray("-0x1"); + QTest::newRow("0xffffffff") << Q_INT64_C(0xffffffff) << QByteArray("0xffffffff"); + QTest::newRow("0xfffffffffffffffe") << Q_INT64_C(0xfffffffffffffffe) << QByteArray("-0x2"); + QTest::newRow("0xffffffffffffffff") << Q_INT64_C(0xffffffffffffffff) << QByteArray("-0x1"); + QTest::newRow("0x7fffffffffffffff") << Q_INT64_C(0x7fffffffffffffff) << QByteArray("0x7fffffffffffffff"); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::hexTest() +{ + QFETCH(qlonglong, number); + QFETCH(QByteArray, data); + + QByteArray array; + QTextStream stream(&array); + + stream << showbase << hex << number; + stream.flush(); + QCOMPARE(array, data); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::binTest_data() +{ + QTest::addColumn<int>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << 0 << QByteArray("0b0"); + QTest::newRow("1") << 1 << QByteArray("0b1"); + QTest::newRow("2") << 2 << QByteArray("0b10"); + QTest::newRow("5") << 5 << QByteArray("0b101"); + QTest::newRow("-1") << -1 << QByteArray("-0b1"); + QTest::newRow("11111111") << 0xff << QByteArray("0b11111111"); + QTest::newRow("1111111111111111") << 0xffff << QByteArray("0b1111111111111111"); + QTest::newRow("1111111011111110") << 0xfefe << QByteArray("0b1111111011111110"); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::binTest() +{ + QFETCH(int, number); + QFETCH(QByteArray, data); + + QByteArray array; + QTextStream stream(&array); + + stream << showbase << bin << number; + stream.flush(); + QCOMPARE(array.constData(), data.constData()); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::octTest_data() +{ + QTest::addColumn<int>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << 0 << QByteArray("00"); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::octTest() +{ + QFETCH(int, number); + QFETCH(QByteArray, data); + + QByteArray array; + QTextStream stream(&array); + + stream << showbase << oct << number; + stream.flush(); + QCOMPARE(array, data); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::zeroTermination() +{ + QTextStream stream; + char c = '@'; + + QTest::ignoreMessage(QtWarningMsg, "QTextStream: No device"); + stream >> c; + QCOMPARE(c, '\0'); + + c = '@'; + + QTest::ignoreMessage(QtWarningMsg, "QTextStream: No device"); + stream >> &c; + QCOMPARE(c, '\0'); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::ws_manipulator() +{ + { + QString string = "a b c d"; + QTextStream stream(&string); + + char a, b, c, d; + stream >> a >> b >> c >> d; + QCOMPARE(a, 'a'); + QCOMPARE(b, ' '); + QCOMPARE(c, 'b'); + QCOMPARE(d, ' '); + } + { + QString string = "a b c d"; + QTextStream stream(&string); + + char a, b, c, d; + stream >> a >> ws >> b >> ws >> c >> ws >> d; + QCOMPARE(a, 'a'); + QCOMPARE(b, 'b'); + QCOMPARE(c, 'c'); + QCOMPARE(d, 'd'); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::stillOpenWhenAtEnd() +{ + int argc = 0; + char **argv = 0; + QCoreApplication app(argc, argv); + + QFile file(SRCDIR "tst_qtextstream.cpp"); + QVERIFY(file.open(QFile::ReadOnly)); + + QTextStream stream(&file); + while (!stream.readLine().isNull()) {} + QVERIFY(file.isOpen()); + +#ifdef Q_OS_WINCE + QSKIP("Qt/CE: Cannot test network on emulator", SkipAll); +#endif + QTcpSocket socket; + socket.connectToHost(QtNetworkSettings::serverName(), 143); +#if defined(Q_OS_SYMBIAN) + // This number is determined in an arbitrary way; whatever it takes + // to make the test pass. + QVERIFY(socket.waitForReadyRead(30000)); +#else + QVERIFY(socket.waitForReadyRead(5000)); +#endif + + QTextStream stream2(&socket); + while (!stream2.readLine().isNull()) {} + QVERIFY(socket.isOpen()); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readNewlines_data() +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<QString>("output"); + + QTest::newRow("empty") << QByteArray() << QString(); + QTest::newRow("\\r\\n") << QByteArray("\r\n") << QString("\n"); + QTest::newRow("\\r\\r\\n") << QByteArray("\r\r\n") << QString("\n"); + QTest::newRow("\\r\\n\\r\\n") << QByteArray("\r\n\r\n") << QString("\n\n"); + QTest::newRow("\\n") << QByteArray("\n") << QString("\n"); + QTest::newRow("\\n\\n") << QByteArray("\n\n") << QString("\n\n"); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readNewlines() +{ + QFETCH(QByteArray, input); + QFETCH(QString, output); + + QBuffer buffer(&input); + buffer.open(QBuffer::ReadOnly | QBuffer::Text); + QTextStream stream(&buffer); + QCOMPARE(stream.readAll(), output); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::seek() +{ + QFile file(SRCDIR "rfc3261.txt"); + QVERIFY(file.open(QFile::ReadOnly)); + + QTextStream stream(&file); + QString tmp; + stream >> tmp; + QCOMPARE(tmp, QString::fromLatin1("Network")); + + // QTextStream::seek(0) should both clear its internal read/write buffers + // and seek the device. + for (int i = 0; i < 4; ++i) { + stream.seek(12 + i); + stream >> tmp; + QCOMPARE(tmp, QString("Network").mid(i)); + } + for (int i = 0; i < 4; ++i) { + stream.seek(16 - i); + stream >> tmp; + QCOMPARE(tmp, QString("Network").mid(4 - i)); + } + stream.seek(139181); + stream >> tmp; + QCOMPARE(tmp, QString("information")); + stream.seek(388683); + stream >> tmp; + QCOMPARE(tmp, QString("telephone")); + + // Also test this with a string + QString words = QLatin1String("thisisa"); + QTextStream stream2(&words, QIODevice::ReadOnly); + stream2 >> tmp; + QCOMPARE(tmp, QString::fromLatin1("thisisa")); + + for (int i = 0; i < 4; ++i) { + stream2.seek(i); + stream2 >> tmp; + QCOMPARE(tmp, QString("thisisa").mid(i)); + } + for (int i = 0; i < 4; ++i) { + stream2.seek(4 - i); + stream2 >> tmp; + QCOMPARE(tmp, QString("thisisa").mid(4 - i)); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::pos() +{ + int argc = 1; + QCoreApplication app(argc, 0); + { + // Strings + QString str("this is a test"); + QTextStream stream(&str, QIODevice::ReadWrite); + + QCOMPARE(stream.pos(), qint64(0)); + for (int i = 0; i <= str.size(); ++i) { + QVERIFY(stream.seek(i)); + QCOMPARE(stream.pos(), qint64(i)); + } + for (int j = str.size(); j >= 0; --j) { + QVERIFY(stream.seek(j)); + QCOMPARE(stream.pos(), qint64(j)); + } + + QVERIFY(stream.seek(0)); + + QChar ch; + stream >> ch; + QCOMPARE(ch, QChar('t')); + + QCOMPARE(stream.pos(), qint64(1)); + QVERIFY(stream.seek(1)); + QCOMPARE(stream.pos(), qint64(1)); + QVERIFY(stream.seek(0)); + + QString strtmp; + stream >> strtmp; + QCOMPARE(strtmp, QString("this")); + + QCOMPARE(stream.pos(), qint64(4)); + stream.seek(0); + stream.seek(4); + + stream >> ch; + QCOMPARE(ch, QChar(' ')); + QCOMPARE(stream.pos(), qint64(5)); + + stream.seek(10); + stream >> strtmp; + QCOMPARE(strtmp, QString("test")); + QCOMPARE(stream.pos(), qint64(14)); + } + { + // Latin1 device + QFile file(SRCDIR "rfc3261.txt"); + QVERIFY(file.open(QIODevice::ReadOnly)); + + QTextStream stream(&file); + + QCOMPARE(stream.pos(), qint64(0)); + + for (int i = 0; i <= file.size(); i += 7) { + QVERIFY(stream.seek(i)); + QCOMPARE(stream.pos(), qint64(i)); + } + for (int j = file.size(); j >= 0; j -= 7) { + QVERIFY(stream.seek(j)); + QCOMPARE(stream.pos(), qint64(j)); + } + + stream.seek(0); + + QString strtmp; + stream >> strtmp; + QCOMPARE(strtmp, QString("Network")); + QCOMPARE(stream.pos(), qint64(19)); + + stream.seek(2598); + QCOMPARE(stream.pos(), qint64(2598)); + stream >> strtmp; + QCOMPARE(stream.pos(), qint64(2607)); + QCOMPARE(strtmp, QString("locations")); + } + { + // Shift-JIS device + for (int i = 0; i < 2; ++i) { + QFile file(SRCDIR "shift-jis.txt"); + if (i == 0) + QVERIFY(file.open(QIODevice::ReadOnly)); + else + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); + + QTextStream stream(&file); + stream.setCodec("Shift-JIS"); + QVERIFY(stream.codec()); + + QCOMPARE(stream.pos(), qint64(0)); + for (int i = 0; i <= file.size(); i += 7) { + QVERIFY(stream.seek(i)); + QCOMPARE(stream.pos(), qint64(i)); + } + for (int j = file.size(); j >= 0; j -= 7) { + QVERIFY(stream.seek(j)); + QCOMPARE(stream.pos(), qint64(j)); + } + + stream.seek(2089); + QString strtmp; + stream >> strtmp; + QCOMPARE(strtmp, QString("AUnicode")); + QCOMPARE(stream.pos(), qint64(2097)); + + stream.seek(43325); + stream >> strtmp; + QCOMPARE(strtmp, QString("Shift-JIS")); + stream >> strtmp; + QCOMPARE(strtmp, QString::fromUtf8("\343\201\247\346\233\270\343\201\213\343\202\214\343\201\237")); + QCOMPARE(stream.pos(), qint64(43345)); + stream >> strtmp; + QCOMPARE(strtmp, QString("POD")); + QCOMPARE(stream.pos(), qint64(43349)); + } + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::pos2() +{ + QByteArray data("abcdef\r\nghijkl\r\n"); + QBuffer buffer(&data); + QVERIFY(buffer.open(QIODevice::ReadOnly | QIODevice::Text)); + + QTextStream stream(&buffer); + + QChar ch; + + QCOMPARE(stream.pos(), qint64(0)); + stream >> ch; + QCOMPARE(ch, QChar('a')); + QCOMPARE(stream.pos(), qint64(1)); + + QString str; + stream >> str; + QCOMPARE(str, QString("bcdef")); + QCOMPARE(stream.pos(), qint64(6)); + + stream >> str; + QCOMPARE(str, QString("ghijkl")); + QCOMPARE(stream.pos(), qint64(14)); + + // Seek back and try again + stream.seek(1); + QCOMPARE(stream.pos(), qint64(1)); + stream >> str; + QCOMPARE(str, QString("bcdef")); + QCOMPARE(stream.pos(), qint64(6)); + + stream.seek(6); + stream >> str; + QCOMPARE(str, QString("ghijkl")); + QCOMPARE(stream.pos(), qint64(14)); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::pos3LargeFile() +{ + { + QFile file(TestFileName); + file.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out( &file ); + // NOTE: The unusual spacing is to ensure non-1-character whitespace. + QString lineString = " 0 1 2\t3 4\t \t5 6 7 8 9 \n"; + // Approximate 50kb text file + const int NbLines = (50*1024) / lineString.length() + 1; + for (int line = 0; line < NbLines; ++line) + out << lineString; + // File is automatically flushed and closed on destruction. + } + QFile file(TestFileName); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QTextStream in( &file ); + const int testValues[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int value; + while (true) { + in.pos(); + for ( int i = 0; i < 10; ++i ) { + in >> value; + if (in.status() != QTextStream::Ok) { + // End case, i == 0 && eof reached. + QCOMPARE(i, 0); + QCOMPARE(in.status(), QTextStream::ReadPastEnd); + return; + } + QCOMPARE(value, testValues[i]); + } + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readStdin() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("Qt/CE and Symbian have no stdin/out support for processes", SkipAll); +#endif + QProcess stdinProcess; + stdinProcess.start("stdinProcess/stdinProcess"); + stdinProcess.setReadChannel(QProcess::StandardError); + + QTextStream stream(&stdinProcess); + stream << "1" << endl; + stream << "2" << endl; + stream << "3" << endl; + + stdinProcess.closeWriteChannel(); + + QVERIFY(stdinProcess.waitForFinished(5000)); + + int a, b, c; + stream >> a >> b >> c; + QCOMPARE(a, 1); + QCOMPARE(b, 2); + QCOMPARE(c, 3); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readAllFromStdin() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("Qt/CE and Symbian have no stdin/out support for processes", SkipAll); +#endif + QProcess stdinProcess; + stdinProcess.start("readAllStdinProcess/readAllStdinProcess", QIODevice::ReadWrite | QIODevice::Text); + stdinProcess.setReadChannel(QProcess::StandardError); + + QTextStream stream(&stdinProcess); + stream.setCodec("ISO-8859-1"); + stream << "hello world" << flush; + + stdinProcess.closeWriteChannel(); + + QVERIFY(stdinProcess.waitForFinished(5000)); + QChar quoteChar('"'); + QCOMPARE(stream.readAll(), QString::fromLatin1("%1hello world%2 \n").arg(quoteChar).arg(quoteChar)); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::readLineFromStdin() +{ +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("Qt/CE and Symbian have no stdin/out support for processes", SkipAll); +#endif + QProcess stdinProcess; + stdinProcess.start("readLineStdinProcess/readLineStdinProcess", QIODevice::ReadWrite | QIODevice::Text); + stdinProcess.setReadChannel(QProcess::StandardError); + + stdinProcess.write("abc\n"); + QVERIFY(stdinProcess.waitForReadyRead(5000)); + QCOMPARE(stdinProcess.readAll().data(), QByteArray("abc").data()); + + stdinProcess.write("def\n"); + QVERIFY(stdinProcess.waitForReadyRead(5000)); + QCOMPARE(stdinProcess.readAll(), QByteArray("def")); + + stdinProcess.closeWriteChannel(); + + QVERIFY(stdinProcess.waitForFinished(5000)); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::read() +{ + { + QFile::remove("testfile"); + QFile file("testfile"); + file.open(QFile::WriteOnly); + file.write("4.15 abc ole"); + file.close(); + + QVERIFY(file.open(QFile::ReadOnly)); + QTextStream stream(&file); + QCOMPARE(stream.read(0), QString("")); + QCOMPARE(stream.read(4), QString("4.15")); + QCOMPARE(stream.read(4), QString(" abc")); + stream.seek(1); + QCOMPARE(stream.read(4), QString(".15 ")); + stream.seek(1); + QCOMPARE(stream.read(4), QString(".15 ")); + stream.seek(2); + QCOMPARE(stream.read(4), QString("15 a")); + // ### add tests for reading \r\n etc.. + } + + { + // File larger than QTEXTSTREAM_BUFFERSIZE + QFile::remove("testfile"); + QFile file("testfile"); + file.open(QFile::WriteOnly); + for (int i = 0; i < 16384 / 8; ++i) + file.write("01234567"); + file.write("0"); + file.close(); + + QVERIFY(file.open(QFile::ReadOnly)); + QTextStream stream(&file); + QCOMPARE(stream.read(10), QString("0123456701")); + QCOMPARE(stream.read(10), QString("2345670123")); + QCOMPARE(stream.readAll().size(), 16385-20); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::qbool() +{ + QString s; + QTextStream stream(&s); + stream << s.contains(QString("hei")); + QCOMPARE(s, QString("0")); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::forcePoint() +{ + QString str; + QTextStream stream(&str); + stream << fixed << forcepoint << 1.0 << " " << 1 << " " << 0 << " " << -1.0 << " " << -1; + QCOMPARE(str, QString("1.000000 1 0 -1.000000 -1")); + + str.clear(); + stream.seek(0); + stream << scientific << forcepoint << 1.0 << " " << 1 << " " << 0 << " " << -1.0 << " " << -1; + QCOMPARE(str, QString("1.000000e+00 1 0 -1.000000e+00 -1")); + + str.clear(); + stream.seek(0); + stream.setRealNumberNotation(QTextStream::SmartNotation); + stream << forcepoint << 1.0 << " " << 1 << " " << 0 << " " << -1.0 << " " << -1; + QCOMPARE(str, QString("1.00000 1 0 -1.00000 -1")); + +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::forceSign() +{ + QString str; + QTextStream stream(&str); + stream << forcesign << 1.2 << " " << -1.2 << " " << 0; + QCOMPARE(str, QString("+1.2 -1.2 +0")); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::read0d0d0a() +{ + QFile file("task113817.txt"); + file.open(QIODevice::ReadOnly | QIODevice::Text); + + QTextStream stream(&file); + while (!stream.atEnd()) + stream.readLine(); +} + +// ------------------------------------------------------------------------------ + +Q_DECLARE_METATYPE(QTextStreamFunction); + +QTextStream &noop(QTextStream &s) { return s; } + +void tst_QTextStream::numeralCase_data() +{ + QTextStreamFunction noop_ = noop; + QTextStreamFunction bin_ = bin; + QTextStreamFunction oct_ = oct; + QTextStreamFunction hex_ = hex; + QTextStreamFunction base = showbase; + QTextStreamFunction ucb = uppercasebase; + QTextStreamFunction lcb = lowercasebase; + QTextStreamFunction ucd = uppercasedigits; + QTextStreamFunction lcd = lowercasedigits; + + QTest::addColumn<QTextStreamFunction>("func1"); + QTest::addColumn<QTextStreamFunction>("func2"); + QTest::addColumn<QTextStreamFunction>("func3"); + QTest::addColumn<QTextStreamFunction>("func4"); + QTest::addColumn<int>("value"); + QTest::addColumn<QString>("expected"); + QTest::newRow("dec 1") << noop_ << noop_ << noop_ << noop_ << 31 << "31"; + QTest::newRow("dec 2") << noop_ << base << noop_ << noop_ << 31 << "31"; + + QTest::newRow("hex 1") << hex_ << noop_ << noop_ << noop_ << 31 << "1f"; + QTest::newRow("hex 2") << hex_ << noop_ << noop_ << lcd << 31 << "1f"; + QTest::newRow("hex 3") << hex_ << noop_ << ucb << noop_ << 31 << "1f"; + QTest::newRow("hex 4") << hex_ << noop_ << noop_ << ucd << 31 << "1F"; + QTest::newRow("hex 5") << hex_ << noop_ << lcb << ucd << 31 << "1F"; + QTest::newRow("hex 6") << hex_ << noop_ << ucb << ucd << 31 << "1F"; + QTest::newRow("hex 7") << hex_ << base << noop_ << noop_ << 31 << "0x1f"; + QTest::newRow("hex 8") << hex_ << base << lcb << lcd << 31 << "0x1f"; + QTest::newRow("hex 9") << hex_ << base << ucb << noop_ << 31 << "0X1f"; + QTest::newRow("hex 10") << hex_ << base << ucb << lcd << 31 << "0X1f"; + QTest::newRow("hex 11") << hex_ << base << noop_ << ucd << 31 << "0x1F"; + QTest::newRow("hex 12") << hex_ << base << lcb << ucd << 31 << "0x1F"; + QTest::newRow("hex 13") << hex_ << base << ucb << ucd << 31 << "0X1F"; + + QTest::newRow("bin 1") << bin_ << noop_ << noop_ << noop_ << 31 << "11111"; + QTest::newRow("bin 2") << bin_ << base << noop_ << noop_ << 31 << "0b11111"; + QTest::newRow("bin 3") << bin_ << base << lcb << noop_ << 31 << "0b11111"; + QTest::newRow("bin 4") << bin_ << base << ucb << noop_ << 31 << "0B11111"; + QTest::newRow("bin 5") << bin_ << base << noop_ << ucd << 31 << "0b11111"; + QTest::newRow("bin 6") << bin_ << base << lcb << ucd << 31 << "0b11111"; + QTest::newRow("bin 7") << bin_ << base << ucb << ucd << 31 << "0B11111"; + + QTest::newRow("oct 1") << oct_ << noop_ << noop_ << noop_ << 31 << "37"; + QTest::newRow("oct 2") << oct_ << base << noop_ << noop_ << 31 << "037"; +} + +// From Task 125496 +void tst_QTextStream::numeralCase() +{ + QFETCH(QTextStreamFunction, func1); + QFETCH(QTextStreamFunction, func2); + QFETCH(QTextStreamFunction, func3); + QFETCH(QTextStreamFunction, func4); + QFETCH(int, value); + QFETCH(QString, expected); + + QString str; + QTextStream stream(&str); + stream << func1 << func2 << func3 << func4 << value; + QCOMPARE(str, expected); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::nanInf() +{ + // Cannot use test data in this function, as comparing nans and infs isn't + // well defined. + QString str("nan NAN nAn +nan +NAN +nAn -nan -NAN -nAn" + " inf INF iNf +inf +INF +iNf -inf -INF -iNf"); + + QTextStream stream(&str); + + double tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsNaN(tmpD)); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD > 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD > 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD > 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD > 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD > 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD > 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD < 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD < 0); tmpD = 0; + stream >> tmpD; QVERIFY(qIsInf(tmpD)); QVERIFY(tmpD < 0); tmpD = 0; + + stream.seek(0); + + float tmpF = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsNaN(tmpF)); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF > 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF > 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF > 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF > 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF > 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF > 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF < 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF < 0); tmpD = 0; + stream >> tmpF; QVERIFY(qIsInf(tmpF)); QVERIFY(tmpF < 0); + + QString s; + QTextStream out(&s); + out << qInf() << " " << -qInf() << " " << qQNaN() + << uppercasedigits << " " + << qInf() << " " << -qInf() << " " << qQNaN() + << flush; + + QCOMPARE(s, QString("inf -inf nan INF -INF NAN")); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::utf8IncompleteAtBufferBoundary_data() +{ + QTest::addColumn<bool>("useLocale"); + + QTest::newRow("utf8") << false; + + // is this locale UTF-8? + if (QString(QChar::ReplacementCharacter).toLocal8Bit() == "\xef\xbf\xbd") + QTest::newRow("locale") << true; +} + +void tst_QTextStream::utf8IncompleteAtBufferBoundary() +{ + QFile::remove(TestFileName); + QFile data(TestFileName); + + QTextCodec *utf8Codec = QTextCodec::codecForMib(106); + QString lineContents = QString::fromUtf8("\342\200\223" // U+2013 EN DASH + "\342\200\223" + "\342\200\223" + "\342\200\223" + "\342\200\223" + "\342\200\223"); + + data.open(QFile::WriteOnly | QFile::Truncate); + { + QTextStream out(&data); + out.setCodec(utf8Codec); + out.setFieldWidth(3); + + for (int i = 0; i < 1000; ++i) { + out << i << lineContents << endl; + } + } + data.close(); + + data.open(QFile::ReadOnly); + QTextStream in(&data); + + QFETCH(bool, useLocale); + if (!useLocale) + in.setCodec(utf8Codec); // QUtf8Codec + else + in.setCodec(QTextCodec::codecForLocale()); + + int i = 0; + do { + QString line = in.readLine().trimmed(); + ++i; + QVERIFY2(line.endsWith(lineContents), QString("Line %1: %2").arg(i).arg(line).toLocal8Bit()); + } while (!in.atEnd()); +} + +// ------------------------------------------------------------------------------ + +// Make sure we don't write a BOM after seek()ing + +void tst_QTextStream::writeSeekWriteNoBOM() +{ + + //First with the default codec (normally either latin-1 or UTF-8) + + QBuffer out; + out.open(QIODevice::WriteOnly); + QTextStream stream(&out); + + int number = 0; + QString sizeStr = QLatin1String("Size=") + + QString::number(number).rightJustified(10, QLatin1Char('0')); + stream << sizeStr << endl; + stream << "Version=" << QString::number(14) << endl; + stream << "blah blah blah" << endl; + stream.flush(); + + QCOMPARE(out.buffer().constData(), "Size=0000000000\nVersion=14\nblah blah blah\n"); + + // Now overwrite the size header item + number = 42; + stream.seek(0); + sizeStr = QLatin1String("Size=") + + QString::number(number).rightJustified(10, QLatin1Char('0')); + stream << sizeStr << endl; + stream.flush(); + + // Check buffer is still OK + QCOMPARE(out.buffer().constData(), "Size=0000000042\nVersion=14\nblah blah blah\n"); + + + //Then UTF-16 + + QBuffer out16; + out16.open(QIODevice::WriteOnly); + QTextStream stream16(&out16); + stream16.setCodec("UTF-16"); + + stream16 << "one" << "two" << QLatin1String("three"); + stream16.flush(); + + // save that output + QByteArray first = out16.buffer(); + + stream16.seek(0); + stream16 << "one"; + stream16.flush(); + + QCOMPARE(out16.buffer(), first); +} + + + +// ------------------------------------------------------------------------------ +void tst_QTextStream::generateOperatorCharData(bool for_QString) +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<QChar>("qchar_output"); + QTest::addColumn<char>("char_output"); + QTest::addColumn<QByteArray>("write_output"); + + QTest::newRow("empty") << QByteArray() << QChar('\0') << '\0' << QByteArray("\0", 1); + QTest::newRow("a") << QByteArray("a") << QChar('a') << 'a' << QByteArray("a"); + QTest::newRow("\\na") << QByteArray("\na") << QChar('\n') << '\n' << QByteArray("\n"); + QTest::newRow("\\0") << QByteArray("\0") << QChar('\0') << '\0' << QByteArray("\0", 1); + QTest::newRow("\\xff") << QByteArray("\xff") << QChar('\xff') << '\xff' << QByteArray("\xff"); + QTest::newRow("\\xfe") << QByteArray("\xfe") << QChar('\xfe') << '\xfe' << QByteArray("\xfe"); + + if (!for_QString) { + QTest::newRow("utf16-BE (empty)") << QByteArray("\xff\xfe", 2) << QChar('\0') << '\0' << QByteArray("\0", 1); + QTest::newRow("utf16-BE (a)") << QByteArray("\xff\xfe\x61\x00", 4) << QChar('a') << 'a' << QByteArray("a"); + QTest::newRow("utf16-LE (empty)") << QByteArray("\xfe\xff", 2) << QChar('\0') << '\0' << QByteArray("\0", 1); + QTest::newRow("utf16-LE (a)") << QByteArray("\xfe\xff\x00\x61", 4) << QChar('a') << 'a' << QByteArray("a"); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::QChar_operators_FromDevice_data() +{ + generateOperatorCharData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::QChar_operators_FromDevice() +{ + QFETCH(QByteArray, input); + QFETCH(QChar, qchar_output); + QFETCH(QByteArray, write_output); + + QBuffer buf(&input); + buf.open(QBuffer::ReadOnly); + QTextStream stream(&buf); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + QChar tmp; + stream >> tmp; + QCOMPARE(tmp, qchar_output); + + QBuffer writeBuf; + writeBuf.open(QBuffer::WriteOnly); + + QTextStream writeStream(&writeBuf); + writeStream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + writeStream << qchar_output; + writeStream.flush(); + + QCOMPARE(writeBuf.buffer().size(), write_output.size()); + QCOMPARE(writeBuf.buffer().constData(), write_output.constData()); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::char_operators_FromDevice_data() +{ + generateOperatorCharData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::char_operators_FromDevice() +{ + QFETCH(QByteArray, input); + QFETCH(char, char_output); + QFETCH(QByteArray, write_output); + + QBuffer buf(&input); + buf.open(QBuffer::ReadOnly); + QTextStream stream(&buf); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + char tmp; + stream >> tmp; + QCOMPARE(tmp, char_output); + + QBuffer writeBuf; + writeBuf.open(QBuffer::WriteOnly); + + QTextStream writeStream(&writeBuf); + writeStream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + writeStream << char_output; + writeStream.flush(); + + QCOMPARE(writeBuf.buffer().size(), write_output.size()); + QCOMPARE(writeBuf.buffer().constData(), write_output.constData()); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::generateNaturalNumbersData(bool for_QString) +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<qulonglong>("output"); + + QTest::newRow("empty") << QByteArray() << qulonglong(0); + QTest::newRow("a") << QByteArray("a") << qulonglong(0); + QTest::newRow(" ") << QByteArray(" ") << qulonglong(0); + QTest::newRow("0") << QByteArray("0") << qulonglong(0); + QTest::newRow("1") << QByteArray("1") << qulonglong(1); + QTest::newRow("12") << QByteArray("12") << qulonglong(12); + QTest::newRow("-12") << QByteArray("-12") << qulonglong(-12); + QTest::newRow("-0") << QByteArray("-0") << qulonglong(0); + QTest::newRow(" 1") << QByteArray(" 1") << qulonglong(1); + QTest::newRow(" \\r\\n\\r\\n123") << QByteArray(" \r\n\r\n123") << qulonglong(123); + + // bit boundary tests + QTest::newRow("127") << QByteArray("127") << qulonglong(127); + QTest::newRow("128") << QByteArray("128") << qulonglong(128); + QTest::newRow("129") << QByteArray("129") << qulonglong(129); + QTest::newRow("-127") << QByteArray("-127") << qulonglong(-127); + QTest::newRow("-128") << QByteArray("-128") << qulonglong(-128); + QTest::newRow("-129") << QByteArray("-129") << qulonglong(-129); + QTest::newRow("32767") << QByteArray("32767") << qulonglong(32767); + QTest::newRow("32768") << QByteArray("32768") << qulonglong(32768); + QTest::newRow("32769") << QByteArray("32769") << qulonglong(32769); + QTest::newRow("-32767") << QByteArray("-32767") << qulonglong(-32767); + QTest::newRow("-32768") << QByteArray("-32768") << qulonglong(-32768); + QTest::newRow("-32769") << QByteArray("-32769") << qulonglong(-32769); + QTest::newRow("65537") << QByteArray("65537") << qulonglong(65537); + QTest::newRow("65536") << QByteArray("65536") << qulonglong(65536); + QTest::newRow("65535") << QByteArray("65535") << qulonglong(65535); + QTest::newRow("-65537") << QByteArray("-65537") << qulonglong(-65537); + QTest::newRow("-65536") << QByteArray("-65536") << qulonglong(-65536); + QTest::newRow("-65535") << QByteArray("-65535") << qulonglong(-65535); + QTest::newRow("2147483646") << QByteArray("2147483646") << qulonglong(2147483646); + QTest::newRow("2147483647") << QByteArray("2147483647") << qulonglong(2147483647); + QTest::newRow("2147483648") << QByteArray("2147483648") << Q_UINT64_C(2147483648); + QTest::newRow("-2147483646") << QByteArray("-2147483646") << qulonglong(-2147483646); + QTest::newRow("-2147483647") << QByteArray("-2147483647") << qulonglong(-2147483647); + QTest::newRow("-2147483648") << QByteArray("-2147483648") << Q_UINT64_C(-2147483648); + QTest::newRow("4294967296") << QByteArray("4294967296") << Q_UINT64_C(4294967296); + QTest::newRow("4294967297") << QByteArray("4294967297") << Q_UINT64_C(4294967297); + QTest::newRow("4294967298") << QByteArray("4294967298") << Q_UINT64_C(4294967298); + QTest::newRow("-4294967296") << QByteArray("-4294967296") << Q_UINT64_C(-4294967296); + QTest::newRow("-4294967297") << QByteArray("-4294967297") << Q_UINT64_C(-4294967297); + QTest::newRow("-4294967298") << QByteArray("-4294967298") << Q_UINT64_C(-4294967298); + QTest::newRow("9223372036854775807") << QByteArray("9223372036854775807") << Q_UINT64_C(9223372036854775807); + QTest::newRow("9223372036854775808") << QByteArray("9223372036854775808") << Q_UINT64_C(9223372036854775808); + QTest::newRow("9223372036854775809") << QByteArray("9223372036854775809") << Q_UINT64_C(9223372036854775809); + QTest::newRow("18446744073709551615") << QByteArray("18446744073709551615") << Q_UINT64_C(18446744073709551615); + QTest::newRow("18446744073709551616") << QByteArray("18446744073709551616") << Q_UINT64_C(0); + QTest::newRow("18446744073709551617") << QByteArray("18446744073709551617") << Q_UINT64_C(1); + // 18446744073709551617 bytes should be enough for anyone.... ;-) + + // hex tests + QTest::newRow("0x0") << QByteArray("0x0") << qulonglong(0); + QTest::newRow("0x") << QByteArray("0x") << qulonglong(0); + QTest::newRow("0x1") << QByteArray("0x1") << qulonglong(1); + QTest::newRow("0xf") << QByteArray("0xf") << qulonglong(15); + QTest::newRow("0xdeadbeef") << QByteArray("0xdeadbeef") << Q_UINT64_C(3735928559); + QTest::newRow("0XDEADBEEF") << QByteArray("0XDEADBEEF") << Q_UINT64_C(3735928559); + QTest::newRow("0xdeadbeefZzzzz") << QByteArray("0xdeadbeefZzzzz") << Q_UINT64_C(3735928559); + QTest::newRow(" 0xdeadbeefZzzzz") << QByteArray(" 0xdeadbeefZzzzz") << Q_UINT64_C(3735928559); + + // oct tests + QTest::newRow("00") << QByteArray("00") << qulonglong(0); + QTest::newRow("0141") << QByteArray("0141") << qulonglong(97); + QTest::newRow("01419999") << QByteArray("01419999") << qulonglong(97); + QTest::newRow(" 01419999") << QByteArray(" 01419999") << qulonglong(97); + + // bin tests + QTest::newRow("0b0") << QByteArray("0b0") << qulonglong(0); + QTest::newRow("0b1") << QByteArray("0b1") << qulonglong(1); + QTest::newRow("0b10") << QByteArray("0b10") << qulonglong(2); + QTest::newRow("0B10") << QByteArray("0B10") << qulonglong(2); + QTest::newRow("0b101010") << QByteArray("0b101010") << qulonglong(42); + QTest::newRow("0b1010102345") << QByteArray("0b1010102345") << qulonglong(42); + QTest::newRow(" 0b1010102345") << QByteArray(" 0b1010102345") << qulonglong(42); + + // utf-16 tests + if (!for_QString) { + QTest::newRow("utf16-BE (empty)") << QByteArray("\xfe\xff", 2) << qulonglong(0); + QTest::newRow("utf16-BE (0xdeadbeef)") + << QByteArray("\xfe\xff" + "\x00\x30\x00\x78\x00\x64\x00\x65\x00\x61\x00\x64\x00\x62\x00\x65\x00\x65\x00\x66", 22) + << Q_UINT64_C(3735928559); + QTest::newRow("utf16-LE (empty)") << QByteArray("\xff\xfe", 2) << Q_UINT64_C(0); + QTest::newRow("utf16-LE (0xdeadbeef)") + << QByteArray("\xff\xfe" + "\x30\x00\x78\x00\x64\x00\x65\x00\x61\x00\x64\x00\x62\x00\x65\x00\x65\x00\x66\x00", 22) + << Q_UINT64_C(3735928559); + } +} + +// ------------------------------------------------------------------------------ +#define IMPLEMENT_STREAM_RIGHT_INT_OPERATOR_TEST(texttype, type) \ + void tst_QTextStream:: texttype##_read_operator_FromDevice_data() \ + { generateNaturalNumbersData(false); } \ + void tst_QTextStream:: texttype##_read_operator_FromDevice() \ + { \ + QFETCH(QByteArray, input); \ + QFETCH(qulonglong, output); \ + type sh; \ + QTextStream stream(&input); \ + stream >> sh; \ + QCOMPARE(sh, (type)output); \ + } +IMPLEMENT_STREAM_RIGHT_INT_OPERATOR_TEST(signedShort, signed short) +IMPLEMENT_STREAM_RIGHT_INT_OPERATOR_TEST(unsignedShort, unsigned short) +IMPLEMENT_STREAM_RIGHT_INT_OPERATOR_TEST(signedInt, signed int) +IMPLEMENT_STREAM_RIGHT_INT_OPERATOR_TEST(unsignedInt, unsigned int) +IMPLEMENT_STREAM_RIGHT_INT_OPERATOR_TEST(qlonglong, qlonglong) +IMPLEMENT_STREAM_RIGHT_INT_OPERATOR_TEST(qulonglong, qulonglong) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::generateRealNumbersData(bool for_QString) +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<double>("output"); + + QTest::newRow("empty") << QByteArray() << 0.0; + QTest::newRow("a") << QByteArray("a") << 0.0; + QTest::newRow("1.0") << QByteArray("1.0") << 1.0; + QTest::newRow(" 1") << QByteArray(" 1") << 1.0; + QTest::newRow(" \\r\\n1.2") << QByteArray(" \r\n1.2") << 1.2; + QTest::newRow("3.14") << QByteArray("3.14") << 3.14; + QTest::newRow("-3.14") << QByteArray("-3.14") << -3.14; + QTest::newRow(" -3.14") << QByteArray(" -3.14") << -3.14; + QTest::newRow("314e-02") << QByteArray("314e-02") << 3.14; + QTest::newRow("314E-02") << QByteArray("314E-02") << 3.14; + QTest::newRow("314e+02") << QByteArray("314e+02") << 31400.; + QTest::newRow("314E+02") << QByteArray("314E+02") << 31400.; + + // ### add numbers with exponents + + if (!for_QString) { + QTest::newRow("utf16-BE (empty)") << QByteArray("\xff\xfe", 2) << 0.0; + QTest::newRow("utf16-LE (empty)") << QByteArray("\xfe\xff", 2) << 0.0; + } +} + +// ------------------------------------------------------------------------------ +#define IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR_TEST(texttype, type) \ + void tst_QTextStream:: texttype##_read_operator_FromDevice_data() \ + { generateRealNumbersData(false); } \ + void tst_QTextStream:: texttype##_read_operator_FromDevice() \ + { \ + QFETCH(QByteArray, input); \ + QFETCH(double, output); \ + type sh; \ + QTextStream stream(&input); \ + stream >> sh; \ + QCOMPARE(sh, (type)output); \ + } +IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR_TEST(float, float) +IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR_TEST(double, double) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::generateStringData(bool for_QString) +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<QByteArray>("array_output"); + QTest::addColumn<QString>("string_output"); + + QTest::newRow("empty") << QByteArray() << QByteArray() << QString(); + QTest::newRow("a") << QByteArray("a") << QByteArray("a") << QString("a"); + QTest::newRow("a b") << QByteArray("a b") << QByteArray("a") << QString("a"); + QTest::newRow(" a b") << QByteArray(" a b") << QByteArray("a") << QString("a"); + QTest::newRow("a1") << QByteArray("a1") << QByteArray("a1") << QString("a1"); + QTest::newRow("a1 b1") << QByteArray("a1 b1") << QByteArray("a1") << QString("a1"); + QTest::newRow(" a1 b1") << QByteArray(" a1 b1") << QByteArray("a1") << QString("a1"); + QTest::newRow("\\n\\n\\nole i dole\\n") << QByteArray("\n\n\nole i dole\n") << QByteArray("ole") << QString("ole"); + + if (!for_QString) { + QTest::newRow("utf16-BE (empty)") << QByteArray("\xff\xfe", 2) << QByteArray() << QString(); + QTest::newRow("utf16-BE (corrupt)") << QByteArray("\xff", 1) << QByteArray("\xff") << QString("\xff"); + QTest::newRow("utf16-LE (empty)") << QByteArray("\xfe\xff", 2) << QByteArray() << QString(); + QTest::newRow("utf16-LE (corrupt)") << QByteArray("\xfe", 1) << QByteArray("\xfe") << QString("\xfe"); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::charPtr_read_operator_FromDevice_data() +{ + generateStringData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::charPtr_read_operator_FromDevice() +{ + QFETCH(QByteArray, input); + QFETCH(QByteArray, array_output); + + QBuffer buffer(&input); + buffer.open(QBuffer::ReadOnly); + QTextStream stream(&buffer); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + char buf[1024]; + stream >> buf; + + QCOMPARE((const char *)buf, array_output.constData()); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::stringRef_read_operator_FromDevice_data() +{ + generateStringData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::stringRef_read_operator_FromDevice() +{ + QFETCH(QByteArray, input); + QFETCH(QString, string_output); + + QBuffer buffer(&input); + buffer.open(QBuffer::ReadOnly); + QTextStream stream(&buffer); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + QString tmp; + stream >> tmp; + + QCOMPARE(tmp, string_output); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::byteArray_read_operator_FromDevice_data() +{ + generateStringData(false); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::byteArray_read_operator_FromDevice() +{ + QFETCH(QByteArray, input); + QFETCH(QByteArray, array_output); + + QBuffer buffer(&input); + buffer.open(QBuffer::ReadOnly); + QTextStream stream(&buffer); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + QByteArray array; + stream >> array; + + QCOMPARE(array, array_output); +} + +// ------------------------------------------------------------------------------ +#define IMPLEMENT_STREAM_LEFT_INT_OPERATOR_TEST(texttype, type) \ + void tst_QTextStream:: texttype##_write_operator_ToDevice() \ + { \ + QFETCH(qulonglong, number); \ + QFETCH(QByteArray, data); \ + \ + QBuffer buffer; \ + buffer.open(QBuffer::WriteOnly); \ + QTextStream stream(&buffer); \ + stream << (type)number; \ + stream.flush(); \ + \ + QCOMPARE(buffer.data().constData(), data.constData()); \ + } + +// ------------------------------------------------------------------------------ +void tst_QTextStream::signedShort_write_operator_ToDevice_data() +{ + QTest::addColumn<qulonglong>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << Q_UINT64_C(0) << QByteArray("0"); + QTest::newRow("1") << Q_UINT64_C(1) << QByteArray("1"); + QTest::newRow("-1") << Q_UINT64_C(-1) << QByteArray("-1"); + QTest::newRow("32767") << Q_UINT64_C(32767) << QByteArray("32767"); + QTest::newRow("32768") << Q_UINT64_C(32768) << QByteArray("-32768"); + QTest::newRow("32769") << Q_UINT64_C(32769) << QByteArray("-32767"); + QTest::newRow("65535") << Q_UINT64_C(65535) << QByteArray("-1"); + QTest::newRow("65536") << Q_UINT64_C(65536) << QByteArray("0"); + QTest::newRow("65537") << Q_UINT64_C(65537) << QByteArray("1"); +} +IMPLEMENT_STREAM_LEFT_INT_OPERATOR_TEST(signedShort, signed short) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::unsignedShort_write_operator_ToDevice_data() +{ + QTest::addColumn<qulonglong>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << Q_UINT64_C(0) << QByteArray("0"); + QTest::newRow("1") << Q_UINT64_C(1) << QByteArray("1"); + QTest::newRow("-1") << Q_UINT64_C(-1) << QByteArray("65535"); + QTest::newRow("32767") << Q_UINT64_C(32767) << QByteArray("32767"); + QTest::newRow("32768") << Q_UINT64_C(32768) << QByteArray("32768"); + QTest::newRow("32769") << Q_UINT64_C(32769) << QByteArray("32769"); + QTest::newRow("65535") << Q_UINT64_C(65535) << QByteArray("65535"); + QTest::newRow("65536") << Q_UINT64_C(65536) << QByteArray("0"); + QTest::newRow("65537") << Q_UINT64_C(65537) << QByteArray("1"); +} +IMPLEMENT_STREAM_LEFT_INT_OPERATOR_TEST(unsignedShort, unsigned short) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::signedInt_write_operator_ToDevice_data() +{ + QTest::addColumn<qulonglong>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << Q_UINT64_C(0) << QByteArray("0"); + QTest::newRow("1") << Q_UINT64_C(1) << QByteArray("1"); + QTest::newRow("-1") << Q_UINT64_C(-1) << QByteArray("-1"); + QTest::newRow("32767") << Q_UINT64_C(32767) << QByteArray("32767"); + QTest::newRow("32768") << Q_UINT64_C(32768) << QByteArray("32768"); + QTest::newRow("32769") << Q_UINT64_C(32769) << QByteArray("32769"); + QTest::newRow("65535") << Q_UINT64_C(65535) << QByteArray("65535"); + QTest::newRow("65536") << Q_UINT64_C(65536) << QByteArray("65536"); + QTest::newRow("65537") << Q_UINT64_C(65537) << QByteArray("65537"); + QTest::newRow("2147483647") << Q_UINT64_C(2147483647) << QByteArray("2147483647"); + QTest::newRow("2147483648") << Q_UINT64_C(2147483648) << QByteArray("-2147483648"); + QTest::newRow("2147483649") << Q_UINT64_C(2147483649) << QByteArray("-2147483647"); + QTest::newRow("4294967295") << Q_UINT64_C(4294967295) << QByteArray("-1"); + QTest::newRow("4294967296") << Q_UINT64_C(4294967296) << QByteArray("0"); + QTest::newRow("4294967297") << Q_UINT64_C(4294967297) << QByteArray("1"); +} +IMPLEMENT_STREAM_LEFT_INT_OPERATOR_TEST(signedInt, signed int) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::unsignedInt_write_operator_ToDevice_data() +{ + QTest::addColumn<qulonglong>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << Q_UINT64_C(0) << QByteArray("0"); + QTest::newRow("1") << Q_UINT64_C(1) << QByteArray("1"); + QTest::newRow("-1") << Q_UINT64_C(-1) << QByteArray("4294967295"); + QTest::newRow("32767") << Q_UINT64_C(32767) << QByteArray("32767"); + QTest::newRow("32768") << Q_UINT64_C(32768) << QByteArray("32768"); + QTest::newRow("32769") << Q_UINT64_C(32769) << QByteArray("32769"); + QTest::newRow("65535") << Q_UINT64_C(65535) << QByteArray("65535"); + QTest::newRow("65536") << Q_UINT64_C(65536) << QByteArray("65536"); + QTest::newRow("65537") << Q_UINT64_C(65537) << QByteArray("65537"); + QTest::newRow("2147483647") << Q_UINT64_C(2147483647) << QByteArray("2147483647"); + QTest::newRow("2147483648") << Q_UINT64_C(2147483648) << QByteArray("2147483648"); + QTest::newRow("2147483649") << Q_UINT64_C(2147483649) << QByteArray("2147483649"); + QTest::newRow("4294967295") << Q_UINT64_C(4294967295) << QByteArray("4294967295"); + QTest::newRow("4294967296") << Q_UINT64_C(4294967296) << QByteArray("0"); + QTest::newRow("4294967297") << Q_UINT64_C(4294967297) << QByteArray("1"); +} +IMPLEMENT_STREAM_LEFT_INT_OPERATOR_TEST(unsignedInt, unsigned int) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::qlonglong_write_operator_ToDevice_data() +{ + QTest::addColumn<qulonglong>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << Q_UINT64_C(0) << QByteArray("0"); + QTest::newRow("1") << Q_UINT64_C(1) << QByteArray("1"); + QTest::newRow("-1") << Q_UINT64_C(-1) << QByteArray("-1"); + QTest::newRow("32767") << Q_UINT64_C(32767) << QByteArray("32767"); + QTest::newRow("32768") << Q_UINT64_C(32768) << QByteArray("32768"); + QTest::newRow("32769") << Q_UINT64_C(32769) << QByteArray("32769"); + QTest::newRow("65535") << Q_UINT64_C(65535) << QByteArray("65535"); + QTest::newRow("65536") << Q_UINT64_C(65536) << QByteArray("65536"); + QTest::newRow("65537") << Q_UINT64_C(65537) << QByteArray("65537"); + QTest::newRow("2147483647") << Q_UINT64_C(2147483647) << QByteArray("2147483647"); + QTest::newRow("2147483648") << Q_UINT64_C(2147483648) << QByteArray("2147483648"); + QTest::newRow("2147483649") << Q_UINT64_C(2147483649) << QByteArray("2147483649"); + QTest::newRow("4294967295") << Q_UINT64_C(4294967295) << QByteArray("4294967295"); + QTest::newRow("4294967296") << Q_UINT64_C(4294967296) << QByteArray("4294967296"); + QTest::newRow("4294967297") << Q_UINT64_C(4294967297) << QByteArray("4294967297"); + QTest::newRow("9223372036854775807") << Q_UINT64_C(9223372036854775807) << QByteArray("9223372036854775807"); + QTest::newRow("9223372036854775808") << Q_UINT64_C(9223372036854775808) << QByteArray("-9223372036854775808"); + QTest::newRow("9223372036854775809") << Q_UINT64_C(9223372036854775809) << QByteArray("-9223372036854775807"); + QTest::newRow("18446744073709551615") << Q_UINT64_C(18446744073709551615) << QByteArray("-1"); +} +IMPLEMENT_STREAM_LEFT_INT_OPERATOR_TEST(qlonglong, qlonglong) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::qulonglong_write_operator_ToDevice_data() +{ + QTest::addColumn<qulonglong>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << Q_UINT64_C(0) << QByteArray("0"); + QTest::newRow("1") << Q_UINT64_C(1) << QByteArray("1"); + QTest::newRow("-1") << Q_UINT64_C(-1) << QByteArray("18446744073709551615"); + QTest::newRow("32767") << Q_UINT64_C(32767) << QByteArray("32767"); + QTest::newRow("32768") << Q_UINT64_C(32768) << QByteArray("32768"); + QTest::newRow("32769") << Q_UINT64_C(32769) << QByteArray("32769"); + QTest::newRow("65535") << Q_UINT64_C(65535) << QByteArray("65535"); + QTest::newRow("65536") << Q_UINT64_C(65536) << QByteArray("65536"); + QTest::newRow("65537") << Q_UINT64_C(65537) << QByteArray("65537"); + QTest::newRow("2147483647") << Q_UINT64_C(2147483647) << QByteArray("2147483647"); + QTest::newRow("2147483648") << Q_UINT64_C(2147483648) << QByteArray("2147483648"); + QTest::newRow("2147483649") << Q_UINT64_C(2147483649) << QByteArray("2147483649"); + QTest::newRow("4294967295") << Q_UINT64_C(4294967295) << QByteArray("4294967295"); + QTest::newRow("4294967296") << Q_UINT64_C(4294967296) << QByteArray("4294967296"); + QTest::newRow("4294967297") << Q_UINT64_C(4294967297) << QByteArray("4294967297"); + QTest::newRow("9223372036854775807") << Q_UINT64_C(9223372036854775807) << QByteArray("9223372036854775807"); + QTest::newRow("9223372036854775808") << Q_UINT64_C(9223372036854775808) << QByteArray("9223372036854775808"); + QTest::newRow("9223372036854775809") << Q_UINT64_C(9223372036854775809) << QByteArray("9223372036854775809"); + QTest::newRow("18446744073709551615") << Q_UINT64_C(18446744073709551615) << QByteArray("18446744073709551615"); +} +IMPLEMENT_STREAM_LEFT_INT_OPERATOR_TEST(qulonglong, qulonglong) + ; + + +// ------------------------------------------------------------------------------ +void tst_QTextStream::generateRealNumbersDataWrite() +{ + QTest::addColumn<double>("number"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("0") << 0.0 << QByteArray("0"); + QTest::newRow("3.14") << 3.14 << QByteArray("3.14"); + QTest::newRow("-3.14") << -3.14 << QByteArray("-3.14"); + QTest::newRow("1.2e+10") << 1.2e+10 << QByteArray("1.2e+10"); + QTest::newRow("-1.2e+10") << -1.2e+10 << QByteArray("-1.2e+10"); +} + +// ------------------------------------------------------------------------------ +#define IMPLEMENT_STREAM_LEFT_REAL_OPERATOR_TEST(texttype, type) \ + void tst_QTextStream:: texttype##_write_operator_ToDevice_data() \ + { generateRealNumbersDataWrite(); } \ + void tst_QTextStream:: texttype##_write_operator_ToDevice() \ + { \ + QFETCH(double, number); \ + QFETCH(QByteArray, data); \ + \ + QBuffer buffer; \ + buffer.open(QBuffer::WriteOnly); \ + QTextStream stream(&buffer); \ + float f = (float)number; \ + stream << f; \ + stream.flush(); \ + QCOMPARE(buffer.data().constData(), data.constData()); \ + } +IMPLEMENT_STREAM_LEFT_REAL_OPERATOR_TEST(float, float) +IMPLEMENT_STREAM_LEFT_REAL_OPERATOR_TEST(double, float) + ; + +// ------------------------------------------------------------------------------ +void tst_QTextStream::string_write_operator_ToDevice_data() +{ + QTest::addColumn<QByteArray>("bytedata"); + QTest::addColumn<QString>("stringdata"); + QTest::addColumn<QByteArray>("result"); + + QTest::newRow("empty") << QByteArray("", 1) << QString(1, '\0') << QByteArray("", 1); + QTest::newRow("a") << QByteArray("a") << QString("a") << QByteArray("a"); + QTest::newRow("a cow jumped over the moon") + << QByteArray("a cow jumped over the moon") + << QString("a cow jumped over the moon") + << QByteArray("a cow jumped over the moon"); + + // ### get the utf16-be test on its legs. + /* + QTest::newRow("utf16-BE (a cow jumped over the moon)") + << QByteArray("\xff\xfe\x00\x61\x00\x20\x00\x63\x00\x6f\x00\x77\x00\x20\x00\x6a\x00\x75\x00\x6d\x00\x70\x00\x65\x00\x64\x00\x20\x00\x6f\x00\x76\x00\x65\x00\x72\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x6d\x00\x6f\x00\x6f\x00\x6e\x00\x0a", 56) + << QString("a cow jumped over the moon") + << QByteArray("a cow jumped over the moon"); + */ +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::string_write_operator_ToDevice() +{ + QFETCH(QByteArray, bytedata); + QFETCH(QString, stringdata); + QFETCH(QByteArray, result); + + { + // char* + QBuffer buf; + buf.open(QBuffer::WriteOnly); + QTextStream stream(&buf); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + stream << bytedata.constData(); + stream.flush(); + QCOMPARE(buf.buffer().constData(), result.constData()); + } + { + // QByteArray + QBuffer buf; + buf.open(QBuffer::WriteOnly); + QTextStream stream(&buf); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + stream << bytedata; + stream.flush(); + QCOMPARE(buf.buffer().constData(), result.constData()); + } + { + // QString + QBuffer buf; + buf.open(QBuffer::WriteOnly); + QTextStream stream(&buf); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + stream << stringdata; + stream.flush(); + QCOMPARE(buf.buffer().constData(), result.constData()); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::useCase1() +{ + QFile::remove("testfile"); + QFile file("testfile"); + QVERIFY(file.open(QFile::ReadWrite)); + + { + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + stream << 4.15 << " " << QByteArray("abc") << " " << QString("ole"); + } + + file.seek(0); + QCOMPARE(file.readAll(), QByteArray("4.15 abc ole")); + file.seek(0); + + { + double d; + QByteArray a; + QString s; + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + stream >> d; + stream >> a; + stream >> s; + + QCOMPARE(d, 4.15); + QCOMPARE(a, QByteArray("abc")); + QCOMPARE(s, QString("ole")); + } +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::useCase2() +{ + QFile::remove("testfile"); + QFile file("testfile"); + QVERIFY(file.open(QFile::ReadWrite)); + + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + + stream << 4.15 << " " << QByteArray("abc") << " " << QString("ole"); + + file.close(); + QVERIFY(file.open(QFile::ReadWrite)); + + QCOMPARE(file.readAll(), QByteArray("4.15 abc ole")); + + file.close(); + QVERIFY(file.open(QFile::ReadWrite)); + + double d; + QByteArray a; + QString s; + QTextStream stream2(&file); + stream2.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream2.setAutoDetectUnicode(true); + + stream2 >> d; + stream2 >> a; + stream2 >> s; + + QCOMPARE(d, 4.15); + QCOMPARE(a, QByteArray("abc")); + QCOMPARE(s, QString("ole")); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::manipulators_data() +{ + QTest::addColumn<int>("flags"); + QTest::addColumn<int>("width"); + QTest::addColumn<double>("realNumber"); + QTest::addColumn<int>("intNumber"); + QTest::addColumn<QString>("textData"); + QTest::addColumn<QByteArray>("result"); + + QTest::newRow("no flags") << 0 << 0 << 5.0 << 5 << QString("five") << QByteArray("55five"); + QTest::newRow("rightadjust") << 0 << 10 << 5.0 << 5 << QString("five") << QByteArray(" 5 5 five"); + + // ### FIX +// QTest::newRow("leftadjust") << int(QTextStream::left) << 10 << 5.0 << 5 << QString("five") << QByteArray("5 5 five "); +// QTest::newRow("showpos") << int(QTextStream::showpos) << 10 << 5.0 << 5 << QString("five") << QByteArray(" +5 +5 five"); +// QTest::newRow("showpos2") << int(QTextStream::showpos) << 5 << 3.14 << -5 << QString("five") << QByteArray("+3.14 -5 five"); +// QTest::newRow("hex") << int(QTextStream::hex | QTextStream::showbase) << 5 << 3.14 << -5 << QString("five") << QByteArray(" 3.14 -0x5 five"); +// QTest::newRow("hex uppercase") << int(QTextStream::hex | QTextStream::uppercase | QTextStream::showbase) << 5 << 3.14 << -5 << QString("five") << QByteArray(" 3.14 -0X5 five"); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::manipulators() +{ +// QFETCH(int, flags); + QFETCH(int, width); + QFETCH(double, realNumber); + QFETCH(int, intNumber); + QFETCH(QString, textData); + QFETCH(QByteArray, result); + + QBuffer buffer; + buffer.open(QBuffer::WriteOnly); + + QTextStream stream(&buffer); + stream.setCodec(QTextCodec::codecForName("ISO-8859-1")); + stream.setAutoDetectUnicode(true); + +// stream.setFlags(flags); + stream.setFieldWidth(width); + stream << realNumber; + stream << intNumber; + stream << textData; + stream.flush(); + + QCOMPARE(buffer.data().constData(), result.constData()); +} + +void tst_QTextStream::generateBOM() +{ + QFile::remove("bom.txt"); + { + QFile file("bom.txt"); + QVERIFY(file.open(QFile::ReadWrite | QFile::Truncate)); + + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-16LE")); + stream << "Hello" << endl; + + file.close(); + QVERIFY(file.open(QFile::ReadOnly)); + QCOMPARE(file.readAll(), QByteArray("\x48\x00\x65\00\x6c\00\x6c\00\x6f\x00\x0a\x00", 12)); + } + + QFile::remove("bom.txt"); + { + QFile file("bom.txt"); + QVERIFY(file.open(QFile::ReadWrite | QFile::Truncate)); + + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-16LE")); + stream << bom << "Hello" << endl; + + file.close(); + QVERIFY(file.open(QFile::ReadOnly)); + QCOMPARE(file.readAll(), QByteArray("\xff\xfe\x48\x00\x65\00\x6c\00\x6c\00\x6f\x00\x0a\x00", 14)); + } +} + +void tst_QTextStream::readBomSeekBackReadBomAgain() +{ + QFile::remove("utf8bom"); + QFile file("utf8bom"); + QVERIFY(file.open(QFile::ReadWrite)); + file.write("\xef\xbb\xbf" "Andreas"); + file.seek(0); + QCOMPARE(file.pos(), qint64(0)); + + QTextStream stream(&file); + stream.setCodec("UTF-8"); + QString Andreas; + stream >> Andreas; + QCOMPARE(Andreas, QString("Andreas")); + stream.seek(0); + stream >> Andreas; + QCOMPARE(Andreas, QString("Andreas")); +} + +// ------------------------------------------------------------------------------ +void tst_QTextStream::status_real_read_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<double>("expected_f"); + QTest::addColumn<QString>("expected_w"); + QTest::addColumn<QList<int> >("results"); + + QTest::newRow("1.23 abc ") << QString("1.23 abc ") << 1.23 << QString("abc") + << (QList<int>() + << (int)QTextStream::Ok + << (int)QTextStream::ReadCorruptData + << (int)QTextStream::Ok + << (int)QTextStream::Ok + << (int)QTextStream::ReadPastEnd); +} + +void tst_QTextStream::status_real_read() +{ + QFETCH(QString, input); + QFETCH(double, expected_f); + QFETCH(QString, expected_w); + QFETCH(QList<int>, results); + + QTextStream s(&input); + double f = 0.0; + QString w; + s >> f; + QCOMPARE((int)s.status(), results.at(0)); + QCOMPARE(f, expected_f); + s >> f; + QCOMPARE((int)s.status(), results.at(1)); + s.resetStatus(); + QCOMPARE((int)s.status(), results.at(2)); + s >> w; + QCOMPARE((int)s.status(), results.at(3)); + QCOMPARE(w, expected_w); + s >> f; + QCOMPARE((int)s.status(), results.at(4)); +} + +void tst_QTextStream::status_integer_read() +{ +#ifdef Q_OS_WINCE + QString text = QLatin1String("123 abc "); + QTextStream s(&text); +#else + QTextStream s("123 abc "); +#endif + int i; + QString w; + s >> i; + QCOMPARE(s.status(), QTextStream::Ok); + s >> i; + QCOMPARE(s.status(), QTextStream::ReadCorruptData); + s.resetStatus(); + QCOMPARE(s.status(), QTextStream::Ok); + s >> w; + QCOMPARE(s.status(), QTextStream::Ok); + QCOMPARE(w, QString("abc")); + s >> i; + QCOMPARE(s.status(), QTextStream::ReadPastEnd); +} + +void tst_QTextStream::status_word_read() +{ +#ifdef Q_OS_WINCE + QString text = QLatin1String("abc "); + QTextStream s(&text); +#else + QTextStream s("abc "); +#endif + QString w; + s >> w; + QCOMPARE(s.status(), QTextStream::Ok); + s >> w; + QCOMPARE(s.status(), QTextStream::ReadPastEnd); +} + +class FakeBuffer : public QBuffer +{ +protected: + qint64 writeData(const char *c, qint64 i) { return m_lock ? 0 : QBuffer::writeData(c, i); } +public: + FakeBuffer(bool locked = false) : m_lock(locked) {} + void setLocked(bool locked) { m_lock = locked; } +private: + bool m_lock; +}; + +void tst_QTextStream::status_write_error() +{ + FakeBuffer fb(false); + QVERIFY(fb.open(QBuffer::ReadWrite)); + QTextStream fs(&fb); + fs.setCodec(QTextCodec::codecForName("latin1")); + /* first write some initial content */ + fs << "hello"; + fs.flush(); + QCOMPARE(fs.status(), QTextStream::Ok); + QCOMPARE(fb.data(), QByteArray("hello")); + /* then test that writing can cause an error */ + fb.setLocked(true); + fs << "error"; + fs.flush(); + QCOMPARE(fs.status(), QTextStream::WriteFailed); + QCOMPARE(fb.data(), QByteArray("hello")); + /* finally test that writing after an error doesn't change the stream any more */ + fb.setLocked(false); + fs << "can't do that"; + fs.flush(); + QCOMPARE(fs.status(), QTextStream::WriteFailed); + QCOMPARE(fb.data(), QByteArray("hello")); +} + +void tst_QTextStream::task180679_alignAccountingStyle() +{ + { + QString result; + QTextStream out(&result); + out.setFieldAlignment(QTextStream::AlignAccountingStyle); + out.setFieldWidth(4); + out.setPadChar('0'); + out << -1; + QCOMPARE(result, QLatin1String("-001")); + } + + { + QString result; + QTextStream out(&result); + out.setFieldAlignment(QTextStream::AlignAccountingStyle); + out.setFieldWidth(4); + out.setPadChar('0'); + out << "-1"; + QCOMPARE(result, QLatin1String("00-1")); + } + + { + QString result; + QTextStream out(&result); + out.setFieldAlignment(QTextStream::AlignAccountingStyle); + out.setFieldWidth(6); + out.setPadChar('0'); + out << -1.2; + QCOMPARE(result, QLatin1String("-001.2")); + } + + { + QString result; + QTextStream out(&result); + out.setFieldAlignment(QTextStream::AlignAccountingStyle); + out.setFieldWidth(6); + out.setPadChar('0'); + out << "-1.2"; + QCOMPARE(result, QLatin1String("00-1.2")); + } +} + +void tst_QTextStream::task178772_setCodec() +{ + QByteArray ba("\xe5 v\xe6r\n\xc3\xa5 v\xc3\xa6r\n"); + QString res = QLatin1String("\xe5 v\xe6r"); + + QTextStream stream(ba); + stream.setCodec("ISO 8859-1"); + QCOMPARE(stream.readLine(),res); + stream.setCodec("UTF-8"); + QCOMPARE(stream.readLine(),res); +} + +void tst_QTextStream::double_write_with_flags_data() +{ + QTest::addColumn<double>("number"); + QTest::addColumn<QString>("output"); + QTest::addColumn<int>("numberFlags"); + QTest::addColumn<int>("realNumberNotation"); + + QTest::newRow("-ForceSign") << -1.23 << QString("-1.23") << (int)QTextStream::ForceSign << 0; + QTest::newRow("+ForceSign") << 1.23 << QString("+1.23") << (int)QTextStream::ForceSign << 0; + QTest::newRow("inf") << qInf() << QString("inf") << 0 << 0; + QTest::newRow("-inf") << -qInf() << QString("-inf") << 0 << 0; + QTest::newRow("inf uppercase") << qInf() << QString("INF") << (int)QTextStream::UppercaseDigits << 0; + QTest::newRow("-inf uppercase") << -qInf() << QString("-INF") << (int)QTextStream::UppercaseDigits << 0; + QTest::newRow("nan") << qQNaN() << QString("nan") << 0 << 0; + QTest::newRow("nan") << qQNaN() << QString("NAN") << (int)QTextStream::UppercaseDigits << 0; + QTest::newRow("scientific") << 1.234567e+02 << QString("1.234567e+02") << 0 << (int)QTextStream::ScientificNotation; + QTest::newRow("scientific2") << 1.234567e+02 << QString("1.234567e+02") << (int)QTextStream::UppercaseBase << (int)QTextStream::ScientificNotation; + QTest::newRow("scientific uppercase") << 1.234567e+02 << QString("1.234567E+02") << (int)QTextStream::UppercaseDigits << (int)QTextStream::ScientificNotation; +} + +void tst_QTextStream::double_write_with_flags() +{ + QFETCH(double, number); + QFETCH(QString, output); + QFETCH(int, numberFlags); + QFETCH(int, realNumberNotation); + + QString buf; + QTextStream stream(&buf); + if (numberFlags) + stream.setNumberFlags(QTextStream::NumberFlag(numberFlags)); + if (realNumberNotation) + stream.setRealNumberNotation(QTextStream::RealNumberNotation(realNumberNotation)); + stream << number; + QCOMPARE(buf, output); +} + +void tst_QTextStream::double_write_with_precision_data() +{ + QTest::addColumn<int>("precision"); + QTest::addColumn<double>("value"); + QTest::addColumn<QString>("result"); + + QTest::ignoreMessage(QtWarningMsg, "QTextStream::setRealNumberPrecision: Invalid precision (-1)"); + QTest::newRow("-1") << -1 << 3.14159 << QString("3.14159"); + QTest::newRow("0") << 0 << 3.14159 << QString("3"); + QTest::newRow("1") << 1 << 3.14159 << QString("3"); + QTest::newRow("2") << 2 << 3.14159 << QString("3.1"); + QTest::newRow("3") << 3 << 3.14159 << QString("3.14"); + QTest::newRow("5") << 5 << 3.14159 << QString("3.1416"); + QTest::newRow("6") << 6 << 3.14159 << QString("3.14159"); + QTest::newRow("7") << 7 << 3.14159 << QString("3.14159"); + QTest::newRow("10") << 10 << 3.14159 << QString("3.14159"); +} + +void tst_QTextStream::double_write_with_precision() +{ + QFETCH(int, precision); + QFETCH(double, value); + QFETCH(QString, result); + + QString buf; + QTextStream stream(&buf); + stream.setRealNumberPrecision(precision); + stream << value; + QCOMPARE(buf, result); +} + +void tst_QTextStream::int_read_with_locale_data() +{ + QTest::addColumn<QString>("locale"); + QTest::addColumn<QString>("input"); + QTest::addColumn<int>("output"); + + QTest::newRow("C -123") << QString("C") << QString("-123") << -123; + QTest::newRow("C +123") << QString("C") << QString("+123") << 123; + QTest::newRow("C 12345") << QString("C") << QString("12345") << 12345; + QTest::newRow("C 12,345") << QString("C") << QString("12,345") << 12; + QTest::newRow("C 12.345") << QString("C") << QString("12.345") << 12; + + QTest::newRow("de_DE -123") << QString("de_DE") << QString("-123") << -123; + QTest::newRow("de_DE +123") << QString("de_DE") << QString("+123") << 123; + QTest::newRow("de_DE 12345") << QString("de_DE") << QString("12345") << 12345; + QTest::newRow("de_DE 12.345") << QString("de_DE") << QString("12.345") << 12345; + QTest::newRow("de_DE .12345") << QString("de_DE") << QString(".12345") << 0; +} + +void tst_QTextStream::int_read_with_locale() +{ + QFETCH(QString, locale); + QFETCH(QString, input); + QFETCH(int, output); + + QTextStream stream(&input); + stream.setLocale(locale); + int result; + stream >> result; + QCOMPARE(result, output); +} + +void tst_QTextStream::int_write_with_locale_data() +{ + QTest::addColumn<QString>("locale"); + QTest::addColumn<int>("numberFlags"); + QTest::addColumn<int>("input"); + QTest::addColumn<QString>("output"); + + QTest::newRow("C -123") << QString("C") << 0 << -123 << QString("-123"); + QTest::newRow("C +123") << QString("C") << (int)QTextStream::ForceSign << 123 << QString("+123"); + QTest::newRow("C 12345") << QString("C") << 0 << 12345 << QString("12345"); + + QTest::newRow("de_DE -123") << QString("de_DE") << 0 << -123 << QString("-123"); + QTest::newRow("de_DE +123") << QString("de_DE") << (int)QTextStream::ForceSign << 123 << QString("+123"); + QTest::newRow("de_DE 12345") << QString("de_DE") << 0 << 12345 << QString("12.345"); +} + +void tst_QTextStream::int_write_with_locale() +{ + QFETCH(QString, locale); + QFETCH(int, numberFlags); + QFETCH(int, input); + QFETCH(QString, output); + + QString result; + QTextStream stream(&result); + stream.setLocale(locale); + if (numberFlags) + stream.setNumberFlags(QTextStream::NumberFlags(numberFlags)); + stream << input; + QCOMPARE(result, output); +} + +// ------------------------------------------------------------------------------ + +// like QTEST_APPLESS_MAIN, but initialising the locale on Unix +#if defined (Q_OS_UNIX) && !defined (Q_OS_SYMBIAN) +QT_BEGIN_NAMESPACE +extern bool qt_locale_initialized; +QT_END_NAMESPACE +#endif + +int main(int argc, char *argv[]) +{ +#if defined (Q_OS_UNIX) && !defined (Q_OS_SYMBIAN) + ::setlocale(LC_ALL, ""); + qt_locale_initialized = true; +#endif + tst_QTextStream tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_qtextstream.moc" + diff --git a/tests/auto/corelib/io/qurl/.gitignore b/tests/auto/corelib/io/qurl/.gitignore new file mode 100644 index 0000000000..c2da731ecd --- /dev/null +++ b/tests/auto/corelib/io/qurl/.gitignore @@ -0,0 +1 @@ +tst_qurl diff --git a/tests/auto/corelib/io/qurl/idna-test.c b/tests/auto/corelib/io/qurl/idna-test.c new file mode 100644 index 0000000000..7effd03168 --- /dev/null +++ b/tests/auto/corelib/io/qurl/idna-test.c @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +struct idna +{ + char *name; + size_t inlen; + unsigned long in[100]; + char *out; + int allowunassigned; + int usestd3asciirules; + int toasciirc; + int tounicoderc; +} idnalist[] = +{ + { + "Arabic (Egyptian)", 17, + { + 0x0644, 0x064A, 0x0647, 0x0645, 0x0627, 0x0628, 0x062A, 0x0643, + 0x0644, 0x0645, 0x0648, 0x0634, 0x0639, 0x0631, 0x0628, 0x064A, + 0x061F}, + IDNA_ACE_PREFIX "egbpdaj6bu4bxfgehfvwxn", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Chinese (simplified)", 9, + { + 0x4ED6, 0x4EEC, 0x4E3A, 0x4EC0, 0x4E48, 0x4E0D, 0x8BF4, 0x4E2D, 0x6587}, + IDNA_ACE_PREFIX "ihqwcrb4cv8a8dqg056pqjye", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Chinese (traditional)", 9, + { + 0x4ED6, 0x5011, 0x7232, 0x4EC0, 0x9EBD, 0x4E0D, 0x8AAA, 0x4E2D, 0x6587}, + IDNA_ACE_PREFIX "ihqwctvzc91f659drss3x8bo0yb", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Czech", 22, + { + 0x0050, 0x0072, 0x006F, 0x010D, 0x0070, 0x0072, 0x006F, 0x0073, + 0x0074, 0x011B, 0x006E, 0x0065, 0x006D, 0x006C, 0x0075, 0x0076, + 0x00ED, 0x010D, 0x0065, 0x0073, 0x006B, 0x0079}, + IDNA_ACE_PREFIX "Proprostnemluvesky-uyb24dma41a", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Hebrew", 22, + { + 0x05DC, 0x05DE, 0x05D4, 0x05D4, 0x05DD, 0x05E4, 0x05E9, 0x05D5, + 0x05D8, 0x05DC, 0x05D0, 0x05DE, 0x05D3, 0x05D1, 0x05E8, 0x05D9, + 0x05DD, 0x05E2, 0x05D1, 0x05E8, 0x05D9, 0x05EA}, + IDNA_ACE_PREFIX "4dbcagdahymbxekheh6e0a7fei0b", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Hindi (Devanagari)", 30, + { + 0x092F, 0x0939, 0x0932, 0x094B, 0x0917, 0x0939, 0x093F, 0x0928, + 0x094D, 0x0926, 0x0940, 0x0915, 0x094D, 0x092F, 0x094B, 0x0902, + 0x0928, 0x0939, 0x0940, 0x0902, 0x092C, 0x094B, 0x0932, 0x0938, + 0x0915, 0x0924, 0x0947, 0x0939, 0x0948, 0x0902}, + IDNA_ACE_PREFIX "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd", 0, 0, + IDNA_SUCCESS + }, { + "Japanese (kanji and hiragana)", 18, + { + 0x306A, 0x305C, 0x307F, 0x3093, 0x306A, 0x65E5, 0x672C, 0x8A9E, + 0x3092, 0x8A71, 0x3057, 0x3066, 0x304F, 0x308C, 0x306A, 0x3044, + 0x306E, 0x304B}, + IDNA_ACE_PREFIX "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa", 0, 0, + IDNA_SUCCESS + }, { + "Russian (Cyrillic)", 28, + { + 0x043F, 0x043E, 0x0447, 0x0435, 0x043C, 0x0443, 0x0436, 0x0435, + 0x043E, 0x043D, 0x0438, 0x043D, 0x0435, 0x0433, 0x043E, 0x0432, + 0x043E, 0x0440, 0x044F, 0x0442, 0x043F, 0x043E, 0x0440, 0x0443, + 0x0441, 0x0441, 0x043A, 0x0438}, + IDNA_ACE_PREFIX "b1abfaaepdrnnbgefbadotcwatmq2g4l", 0, 0, + IDNA_SUCCESS, IDNA_SUCCESS + }, { + "Spanish", 40, + { + 0x0050, 0x006F, 0x0072, 0x0071, 0x0075, 0x00E9, 0x006E, 0x006F, + 0x0070, 0x0075, 0x0065, 0x0064, 0x0065, 0x006E, 0x0073, 0x0069, + 0x006D, 0x0070, 0x006C, 0x0065, 0x006D, 0x0065, 0x006E, 0x0074, + 0x0065, 0x0068, 0x0061, 0x0062, 0x006C, 0x0061, 0x0072, 0x0065, + 0x006E, 0x0045, 0x0073, 0x0070, 0x0061, 0x00F1, 0x006F, 0x006C}, + IDNA_ACE_PREFIX "PorqunopuedensimplementehablarenEspaol-fmd56a", 0, 0, + IDNA_SUCCESS + }, { + "Vietnamese", 31, + { + 0x0054, 0x1EA1, 0x0069, 0x0073, 0x0061, 0x006F, 0x0068, 0x1ECD, + 0x006B, 0x0068, 0x00F4, 0x006E, 0x0067, 0x0074, 0x0068, 0x1EC3, + 0x0063, 0x0068, 0x1EC9, 0x006E, 0x00F3, 0x0069, 0x0074, 0x0069, + 0x1EBF, 0x006E, 0x0067, 0x0056, 0x0069, 0x1EC7, 0x0074}, + IDNA_ACE_PREFIX "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g", 0, 0, + IDNA_SUCCESS + }, { + "Japanese", 8, + { + 0x0033, 0x5E74, 0x0042, 0x7D44, 0x91D1, 0x516B, 0x5148, 0x751F}, + IDNA_ACE_PREFIX "3B-ww4c5e180e575a65lsy2b", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Japanese", 24, + { + 0x5B89, 0x5BA4, 0x5948, 0x7F8E, 0x6075, 0x002D, 0x0077, 0x0069, + 0x0074, 0x0068, 0x002D, 0x0053, 0x0055, 0x0050, 0x0045, 0x0052, + 0x002D, 0x004D, 0x004F, 0x004E, 0x004B, 0x0045, 0x0059, 0x0053}, + IDNA_ACE_PREFIX "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n", 0, 0, + IDNA_SUCCESS + }, { + "Japanese", 25, + { + 0x0048, 0x0065, 0x006C, 0x006C, 0x006F, 0x002D, 0x0041, 0x006E, + 0x006F, 0x0074, 0x0068, 0x0065, 0x0072, 0x002D, 0x0057, 0x0061, + 0x0079, 0x002D, 0x305D, 0x308C, 0x305E, 0x308C, 0x306E, 0x5834, + 0x6240}, + IDNA_ACE_PREFIX "Hello-Another-Way--fc4qua05auwb3674vfr0b", 0, 0, + IDNA_SUCCESS + }, { + "Japanese", 8, + { + 0x3072, 0x3068, 0x3064, 0x5C4B, 0x6839, 0x306E, 0x4E0B, 0x0032}, + IDNA_ACE_PREFIX "2-u9tlzr9756bt3uc0v", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Japanese", 13, + { + 0x004D, 0x0061, 0x006A, 0x0069, 0x3067, 0x004B, 0x006F, 0x0069, + 0x3059, 0x308B, 0x0035, 0x79D2, 0x524D}, + IDNA_ACE_PREFIX "MajiKoi5-783gue6qz075azm5e", 0, 0, IDNA_SUCCESS, + IDNA_SUCCESS + }, { + "Japanese", 9, + { + 0x30D1, 0x30D5, 0x30A3, 0x30FC, 0x0064, 0x0065, 0x30EB, 0x30F3, 0x30D0}, + IDNA_ACE_PREFIX "de-jg4avhby1noc0d", 0, 0, IDNA_SUCCESS, IDNA_SUCCESS + }, { + "Japanese", 7, + { + 0x305D, 0x306E, 0x30B9, 0x30D4, 0x30FC, 0x30C9, 0x3067}, + IDNA_ACE_PREFIX "d9juau41awczczp", 0, 0, IDNA_SUCCESS, IDNA_SUCCESS + }, { + "Greek", 8, + {0x03b5, 0x03bb, 0x03bb, 0x03b7, 0x03bd, 0x03b9, 0x03ba, 0x03ac}, + IDNA_ACE_PREFIX "hxargifdar", 0, 0, IDNA_SUCCESS, IDNA_SUCCESS + }, { + "Maltese (Malti)", 10, + {0x0062, 0x006f, 0x006e, 0x0121, 0x0075, 0x0073, 0x0061, 0x0127, + 0x0127, 0x0061}, + IDNA_ACE_PREFIX "bonusaa-5bb1da", 0, 0, IDNA_SUCCESS, IDNA_SUCCESS + }, { + "Russian (Cyrillic)", 28, + {0x043f, 0x043e, 0x0447, 0x0435, 0x043c, 0x0443, 0x0436, 0x0435, + 0x043e, 0x043d, 0x0438, 0x043d, 0x0435, 0x0433, 0x043e, 0x0432, + 0x043e, 0x0440, 0x044f, 0x0442, 0x043f, 0x043e, 0x0440, 0x0443, + 0x0441, 0x0441, 0x043a, 0x0438}, + IDNA_ACE_PREFIX "b1abfaaepdrnnbgefbadotcwatmq2g4l", 0, 0, + IDNA_SUCCESS, IDNA_SUCCESS + } +}; diff --git a/tests/auto/corelib/io/qurl/qurl.pro b/tests/auto/corelib/io/qurl/qurl.pro new file mode 100644 index 0000000000..a43a57e002 --- /dev/null +++ b/tests/auto/corelib/io/qurl/qurl.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qurl.cpp +QT = core core-private +symbian: TARGET.CAPABILITY = NetworkServices +CONFIG += parallel_test diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp new file mode 100644 index 0000000000..d7f7742d46 --- /dev/null +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -0,0 +1,4049 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore/QDebug> + +#include <qcoreapplication.h> + +#include <qfileinfo.h> +#include <qurl.h> +#include <qtextcodec.h> +#include <qmap.h> +#include "private/qtldurl_p.h" + +// For testsuites +#define IDNA_ACE_PREFIX "xn--" +#define IDNA_SUCCESS 1 +#define STRINGPREP_NO_UNASSIGNED 1 +#define STRINGPREP_CONTAINS_UNASSIGNED 2 +#define STRINGPREP_CONTAINS_PROHIBITED 3 +#define STRINGPREP_BIDI_BOTH_L_AND_RAL 4 +#define STRINGPREP_BIDI_LEADTRAIL_NOT_RAL 5 + +struct ushortarray { + ushortarray(unsigned short *array = 0) + { + if (array) + memcpy(points, array, sizeof(points)); + } + + unsigned short points[100]; +}; + +Q_DECLARE_METATYPE(ushortarray) +Q_DECLARE_METATYPE(QUrl::FormattingOptions) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QUrl : public QObject +{ + Q_OBJECT + +public: + tst_QUrl(); + virtual ~tst_QUrl(); + + +public slots: + void init(); + void cleanup(); +private slots: + void effectiveTLDs_data(); + void effectiveTLDs(); + void getSetCheck(); + void constructing(); + void assignment(); + void comparison(); + void copying(); + void setUrl(); + void i18n_data(); + void i18n(); + void punycode_data(); + void punycode(); + void resolving_data(); + void resolving(); + void toString_data(); + void toString(); + void toString_constructed_data(); + void toString_constructed(); + void isParentOf_data(); + void isParentOf(); + void toLocalFile_data(); + void toLocalFile(); + void fromLocalFile_data(); + void fromLocalFile(); + void relative(); + void compat_legacy(); + void compat_constructor_01_data(); + void compat_constructor_01(); + void compat_constructor_02_data(); + void compat_constructor_02(); + void compat_constructor_03_data(); + void compat_constructor_03(); + void compat_isValid_01_data(); + void compat_isValid_01(); + void compat_isValid_02_data(); + void compat_isValid_02(); + void compat_path_data(); + void compat_path(); + void compat_fileName_data(); + void compat_fileName(); + void compat_decode_data(); + void compat_decode(); + void compat_encode_data(); + void compat_encode(); + void percentEncoding_data(); + void percentEncoding(); + void swap(); + void symmetry(); + void ipv6_data(); + void ipv6(); + void ipv6_2_data(); + void ipv6_2(); + void moreIpv6(); + void toPercentEncoding_data(); + void toPercentEncoding(); + void isRelative_data(); + void isRelative(); + void queryItems(); + void hasQuery_data(); + void hasQuery(); + void hasQueryItem_data(); + void hasQueryItem(); + void nameprep(); + void isValid(); + void schemeValidator_data(); + void schemeValidator(); + void invalidSchemeValidator(); + void tolerantParser(); + void correctEncodedMistakes_data(); + void correctEncodedMistakes(); + void correctDecodedMistakes_data(); + void correctDecodedMistakes(); + void idna_testsuite_data(); + void idna_testsuite(); + void nameprep_testsuite_data(); + void nameprep_testsuite(); + void nameprep_highcodes_data(); + void nameprep_highcodes(); + void ace_testsuite_data(); + void ace_testsuite(); + void std3violations_data(); + void std3violations(); + void std3deviations_data(); + void std3deviations(); + void tldRestrictions_data(); + void tldRestrictions(); + void emptyQueryOrFragment(); + void hasFragment_data(); + void hasFragment(); + void setEncodedFragment_data(); + void setEncodedFragment(); + void fromEncoded(); + void stripTrailingSlash(); + void hosts_data(); + void hosts(); + void setPort(); + void toEncoded_data(); + void toEncoded(); + void setAuthority_data(); + void setAuthority(); + void errorString(); + void clear(); + void resolvedWithAbsoluteSchemes() const; + void resolvedWithAbsoluteSchemes_data() const; + void binaryData_data(); + void binaryData(); + void fromUserInput_data(); + void fromUserInput(); + void task_199967(); + void task_240612(); + void taskQTBUG_6962(); + void taskQTBUG_8701(); + void removeAllEncodedQueryItems_data(); + void removeAllEncodedQueryItems(); +}; + +// Testing get/set functions +void tst_QUrl::getSetCheck() +{ + QUrl obj1; + // int QUrl::port() + // void QUrl::setPort(int) + obj1.setPort(0); + QCOMPARE(0, obj1.port()); + + QTest::ignoreMessage(QtWarningMsg, "QUrl::setPort: Out of range"); + obj1.setPort(INT_MIN); + QCOMPARE(-1, obj1.port()); // Out of range, -1 + + QTest::ignoreMessage(QtWarningMsg, "QUrl::setPort: Out of range"); + obj1.setPort(INT_MAX); + QCOMPARE(-1, obj1.port()); // Out of range, -1 + + obj1.setPort(1234); + QCOMPARE(1234, obj1.port()); + + // static QStringList QUrl::idnWhitelist() + // static void QUrl::setIdnWhitelist(QStringList) + QStringList original = QUrl::idnWhitelist(); // save for later + + QUrl::setIdnWhitelist(QStringList()); + QCOMPARE(QUrl::idnWhitelist(), QStringList()); + + QStringList norway; norway << "no"; + QUrl::setIdnWhitelist(norway); + QCOMPARE(QUrl::idnWhitelist(), norway); + + QStringList modified = original; + modified << "foo"; + QUrl::setIdnWhitelist(modified); + QCOMPARE(QUrl::idnWhitelist(), modified); + + // reset to the original + QUrl::setIdnWhitelist(original); + QCOMPARE(QUrl::idnWhitelist(), original); +} + +tst_QUrl::tst_QUrl() +{ +} + +tst_QUrl::~tst_QUrl() +{ + +} + +void tst_QUrl::init() +{ +} + +void tst_QUrl::cleanup() +{ +} + +void tst_QUrl::constructing() +{ + QUrl url; + QVERIFY(!url.isValid()); + QVERIFY(url.isEmpty()); + QCOMPARE(url.port(), -1); + QCOMPARE(url.toString(), QString()); + + QList<QPair<QString, QString> > query; + query += qMakePair(QString("type"), QString("login")); + query += qMakePair(QString("name"), QString("åge nissemannsen")); + query += qMakePair(QString("ole&du"), QString("anne+jørgen=sant")); + query += qMakePair(QString("prosent"), QString("%")); + url.setQueryItems(query); + QVERIFY(!url.isEmpty()); + + QCOMPARE(url.encodedQuery().constData(), + QByteArray("type=login&name=%C3%A5ge%20nissemannsen&ole%26du=" + "anne+j%C3%B8rgen%3Dsant&prosent=%25").constData()); + + url.setQueryDelimiters('>', '/'); + url.setQueryItems(query); + + QCOMPARE(url.encodedQuery(), + QByteArray("type>login/name>%C3%A5ge%20nissemannsen/ole&du>" + "anne+j%C3%B8rgen=sant/prosent>%25")); + + url.setFragment(QString::fromLatin1("top")); + QCOMPARE(url.fragment(), QString::fromLatin1("top")); + + url.setScheme("http"); + url.setHost("qt.nokia.com"); + + QCOMPARE(url.toString(), + QString::fromLatin1("http://qt.nokia.com?type>login/name>åge nissemannsen" + "/ole&du>anne+jørgen=sant/prosent>%#top")); + + QUrl justHost("qt.nokia.com"); + QVERIFY(!justHost.isEmpty()); + QVERIFY(justHost.host().isEmpty()); + QCOMPARE(justHost.path(), QString::fromLatin1("qt.nokia.com")); + + QUrl hostWithSlashes("//qt.nokia.com"); + QVERIFY(hostWithSlashes.path().isEmpty()); + QCOMPARE(hostWithSlashes.host(), QString::fromLatin1("qt.nokia.com")); + + + QUrl withHashInPath; + withHashInPath.setPath(QString::fromLatin1("hi#mum.txt")); + QCOMPARE(withHashInPath.path(), QString::fromLatin1("hi#mum.txt")); + QCOMPARE(withHashInPath.toEncoded(), QByteArray("hi%23mum.txt")); + QUrl fromHashInPath = QUrl::fromEncoded(withHashInPath.toEncoded()); + QVERIFY(withHashInPath == fromHashInPath); + + + QUrl buildUNC; + buildUNC.setScheme(QString::fromLatin1("file")); + buildUNC.setHost(QString::fromLatin1("somehost")); + buildUNC.setPath(QString::fromLatin1("somepath")); + QCOMPARE(buildUNC.toLocalFile(), QString::fromLatin1("//somehost/somepath")); + buildUNC.toEncoded(); + QVERIFY(!buildUNC.isEmpty()); +} + +void tst_QUrl::assignment() +{ + QUrl url("http://qt.nokia.com/"); + QVERIFY(url.isValid()); + + QUrl copy; + copy = url; + + QVERIFY(url == copy); +} + +void tst_QUrl::comparison() +{ + QUrl url1("http://qt.nokia.com/"); + QVERIFY(url1.isValid()); + + QUrl url2("http://qt.nokia.com/"); + QVERIFY(url2.isValid()); + + QVERIFY(url1 == url2); + + // 6.2.2 Syntax-based Normalization + QUrl url3 = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D"); + QUrl url4 = QUrl::fromEncoded("eXAMPLE://a/./b/../b/%63/%7bfoo%7d"); + QVERIFY(url3 == url4); + + // 6.2.2.1 Make sure hexdecimal characters in percent encoding are + // treated case-insensitively + QUrl url5; + url5.setEncodedQuery("a=%2a"); + QUrl url6; + url6.setEncodedQuery("a=%2A"); + QVERIFY(url5 == url6); + + // ensure that encoded characters in the query do not match + QUrl url7; + url7.setEncodedQuery("a=%63"); + QUrl url8; + url8.setEncodedQuery("a=c"); + QVERIFY(url7 != url8); +} + +void tst_QUrl::copying() +{ + QUrl url("http://qt.nokia.com/"); + QVERIFY(url.isValid()); + + QUrl copy(url); + + QVERIFY(url == copy); +} + +void tst_QUrl::setUrl() +{ + { + QUrl url("http://0.foo.com"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString::fromLatin1("http")); + QCOMPARE(url.path(), QString()); + QCOMPARE(url.host(), QString::fromLatin1("0.foo.com")); + } + + { + QUrl url("file:/"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString::fromLatin1("file")); + QCOMPARE(url.path(), QString::fromLatin1("/")); + QVERIFY(url.encodedQuery().isEmpty()); + QVERIFY(url.userInfo().isEmpty()); + QVERIFY(url.authority().isEmpty()); + QVERIFY(url.fragment().isEmpty()); + QCOMPARE(url.port(), -1); + } + + { + QUrl url("hTTp://www.foo.bar:80"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString::fromLatin1("hTTp")); + QCOMPARE(url.path(), QString()); + QVERIFY(url.encodedQuery().isEmpty()); + QVERIFY(url.userInfo().isEmpty()); + QVERIFY(url.fragment().isEmpty()); + QCOMPARE(url.host(), QString::fromLatin1("www.foo.bar")); + QCOMPARE(url.authority(), QString::fromLatin1("www.foo.bar:80")); + QCOMPARE(url.port(), 80); + + QUrl url2("//www1.foo.bar"); + QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("hTTp://www1.foo.bar")); + } + + { + QUrl url("http://user:pass@[56::56:56:56:127.0.0.1]:99"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString::fromLatin1("http")); + QCOMPARE(url.path(), QString()); + QVERIFY(url.encodedQuery().isEmpty()); + QCOMPARE(url.userInfo(), QString::fromLatin1("user:pass")); + QVERIFY(url.fragment().isEmpty()); + QCOMPARE(url.host(), QString::fromLatin1("56::56:56:56:127.0.0.1")); + QCOMPARE(url.authority(), QString::fromLatin1("user:pass@[56::56:56:56:127.0.0.1]:99")); + QCOMPARE(url.port(), 99); + } + + { + QUrl url("http://www.foo.bar"); + QVERIFY(url.isValid()); + + QUrl url2("/top//test/../test1/file.html"); + QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("http://www.foo.bar/top//test1/file.html")); + } + + { + QUrl url("http://www.foo.bar"); + QVERIFY(url.isValid()); + + QUrl url2("/top//test/../test1/file.html"); + QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("http://www.foo.bar/top//test1/file.html")); + } + + { + QUrl url("http://www.foo.bar/top//test2/file2.html"); + QVERIFY(url.isValid()); + + QCOMPARE(url.toString(), QString::fromLatin1("http://www.foo.bar/top//test2/file2.html")); + } + + { + QUrl url("http://www.foo.bar/top//test2/file2.html"); + QVERIFY(url.isValid()); + + QCOMPARE(url.toString(), QString::fromLatin1("http://www.foo.bar/top//test2/file2.html")); + } + + { + QUrl url("file:/usr/local/src/kde2/////kdelibs/kio"); + QVERIFY(url.isValid()); + QCOMPARE(url.toString(), QString::fromLatin1("file:///usr/local/src/kde2/////kdelibs/kio")); + } + + { + QUrl url("http://www.foo.bar"); + QVERIFY(url.isValid()); + + QUrl url2("mailto:bastian@kde.org"); + QVERIFY(url2.isValid()); + QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("mailto:bastian@kde.org")); + } + + { + QUrl url("mailto:bastian@kde.org?subject=hello"); + QCOMPARE(url.toString(), QString::fromLatin1("mailto:bastian@kde.org?subject=hello")); + } + + { + QUrl url("file:/usr/local/src/kde2/kdelibs/kio/"); + QVERIFY(url.isValid()); + + QUrl url2("../../////kdebase/konqueror"); + QCOMPARE(url.resolved(url2).toString(), + QString::fromLatin1("file:///usr/local/src/kde2/////kdebase/konqueror")); + } + + { + QString u1 = "file:/home/dfaure/my#myref"; + QUrl url = u1; + QVERIFY(url.isValid()); + QCOMPARE(url.toString(), QString::fromLatin1("file:///home/dfaure/my#myref")); + QCOMPARE(url.fragment(), QString::fromLatin1("myref")); + } + + { + QString u1 = "file:/home/dfaure/my#myref"; + QUrl url = u1; + QVERIFY(url.isValid()); + + QCOMPARE(url.toString(), QString::fromLatin1("file:///home/dfaure/my#myref")); + QCOMPARE(url.fragment(), QString::fromLatin1("myref")); + } + + { + QUrl url("gg:www.kde.org"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString::fromLatin1("gg")); + QVERIFY(url.host().isEmpty()); + QCOMPARE(url.path(), QString::fromLatin1("www.kde.org")); + } + + { + QUrl url("KDE"); + QVERIFY(url.isValid()); + QCOMPARE(url.path(), QString::fromLatin1("KDE")); + QVERIFY(url.scheme().isEmpty()); + } + + { + QUrl url("$HOME/.kde/share/config"); + QVERIFY(url.isValid()); + QCOMPARE(url.path(), QString::fromLatin1("$HOME/.kde/share/config")); + QVERIFY(url.scheme().isEmpty()); + } + + { + QUrl url("file:/opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject::connect"); + QVERIFY(url.isValid()); + QCOMPARE(url.fragment(), QString::fromLatin1("QObject::connect")); + } + + { + QUrl url("file:/opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject:connect"); + QVERIFY(url.isValid()); + QCOMPARE(url.fragment(), QString::fromLatin1("QObject:connect")); + } + + { + // suburls + QUrl url("file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/#myref"); + QVERIFY(url.isValid()); + + // or simply 'myref?' + QCOMPARE(url.fragment(), QString::fromLatin1("gzip:/#tar:/#myref")); + } + + { + QUrl url("error:/?error=14&errText=Unknown%20host%20asdfu.adgi.sdfgoi#http://asdfu.adgi.sdfgoi"); + QVERIFY(url.isValid()); + QCOMPARE(url.fragment(), QString::fromLatin1("http://asdfu.adgi.sdfgoi")); + } + + { + // suburls + QUrl url("file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/"); + QVERIFY(url.isValid()); + } + + { + QUrl url("file:/home/dfaure/cdrdao-1.1.5/dao/#CdrDriver.cc#"); + QVERIFY(url.isValid()); + } + + { + QUrl url("file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/README"); + QVERIFY(url.isValid()); + QCOMPARE(url.toString(), QString::fromLatin1("file:///home/dfaure/my tar file.tgz#gzip:/#tar:/README")); + } + + { + QUrl notPretty; + notPretty.setEncodedUrl("http://ferret.lmh.ox.ac.uk/%7Ekdecvs/"); + QVERIFY(notPretty.isValid()); + QCOMPARE(notPretty.toString(), QString::fromLatin1("http://ferret.lmh.ox.ac.uk/~kdecvs/")); + + QUrl notPretty2; + notPretty2.setEncodedUrl("file:/home/test/directory%20with%20spaces"); + QVERIFY(notPretty2.isValid()); + QCOMPARE(notPretty2.toString(), QString::fromLatin1("file:///home/test/directory with spaces")); + + QUrl notPretty3("fish://foo/%23README%23"); + QVERIFY(notPretty3.isValid()); + QCOMPARE(notPretty3.toString(), QString::fromLatin1("fish://foo/%23README%23")); + + QUrl url15581; + url15581.setUrl("http://alain.knaff.linux.lu/bug-reports/kde/spaces in url.html"); + QCOMPARE(url15581.toString(), QString::fromLatin1("http://alain.knaff.linux.lu/bug-reports/kde/spaces in url.html")); + QCOMPARE(url15581.toEncoded().constData(), QByteArray("http://alain.knaff.linux.lu/bug-reports/kde/spaces%20in%20url.html").constData()); + + QUrl url15582("http://alain.knaff.linux.lu/bug-reports/kde/percentage%in%url.html"); + QCOMPARE(url15582.toString(), QString::fromLatin1("http://alain.knaff.linux.lu/bug-reports/kde/percentage%in%url.html")); + QCOMPARE(url15582.toEncoded(), QByteArray("http://alain.knaff.linux.lu/bug-reports/kde/percentage%25in%25url.html")); + } + + { + QUrl carsten; + carsten.setPath("/home/gis/src/kde/kdelibs/kfile/.#kfiledetailview.cpp.1.18"); + QCOMPARE(carsten.path(), QString::fromLatin1("/home/gis/src/kde/kdelibs/kfile/.#kfiledetailview.cpp.1.18")); + + QUrl charles; + charles.setPath("/home/charles/foo%20moo"); + QCOMPARE(charles.path(), QString::fromLatin1("/home/charles/foo%20moo")); + + QUrl charles2; + charles2.setEncodedUrl("file:/home/charles/foo%20moo"); + QCOMPARE(charles2.path(), QString::fromLatin1("/home/charles/foo moo")); + } + + { + QUrl udir; + QCOMPARE(udir.toEncoded(), QByteArray()); + QVERIFY(!udir.isValid()); + + udir = QUrl::fromLocalFile("/home/dfaure/file.txt"); + QCOMPARE(udir.path(), QString::fromLatin1("/home/dfaure/file.txt")); + QCOMPARE(udir.toEncoded(), QByteArray("file:///home/dfaure/file.txt")); + } + + { + QUrl url; + url.setUrl("hello.com#?"); + QVERIFY(url.isValid()); + url.setUrl("hello.com"); + QVERIFY(!url.toString().contains(QLatin1Char('#'))); + QVERIFY(!url.toString().contains(QLatin1Char('?'))); + } + + { + QUrl url; + url.setUrl("http://1.2.3.4.example.com"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString("http")); + QCOMPARE(url.host(), QString("1.2.3.4.example.com")); + } + + { + QUrl url; + url.setUrl("http://1.2.3.4"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString("http")); + QCOMPARE(url.host(), QString("1.2.3.4")); + } + { + QUrl url; + url.setUrl("http://1.2.3.4/"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString("http")); + QCOMPARE(url.host(), QString("1.2.3.4")); + QCOMPARE(url.path(), QString("/")); + } + { + QUrl url; + url.setUrl("http://1.2.3.4?foo"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString("http")); + QCOMPARE(url.host(), QString("1.2.3.4")); + QCOMPARE(url.encodedQuery(), QByteArray("foo")); + } + { + QUrl url; + url.setUrl("http://1.2.3.4#bar"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString("http")); + QCOMPARE(url.host(), QString("1.2.3.4")); + QCOMPARE(url.fragment(), QString("bar")); + } + + { + QUrl url; + url.setEncodedUrl("data:text/javascript,d5%20%3D%20'five\\u0027s'%3B"); + QVERIFY(url.isValid()); + QCOMPARE(url.scheme(), QString("data")); + QCOMPARE(url.host(), QString()); + QCOMPARE(url.path(), QString("text/javascript,d5 = 'five\\u0027s';")); + QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20%3D%20'five%5Cu0027s'%3B"); + } + + { //check it calls detach + QUrl u1("http://aaa.com"); + QUrl u2 = u1; + u2.setUrl("http://bbb.com"); + QCOMPARE(u1.host(), QString::fromLatin1("aaa.com")); + QCOMPARE(u2.host(), QString::fromLatin1("bbb.com")); + } + +/* + The tests below are copied from kdelibs/kdecore/tests/kurltest.cpp (an old version of) + + Copyright (c) 1999-2005 Waldo Bastian <bastian@kde.org> + Copyright (c) 2000-2005 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +/* + ### File / directory specifics + + KURL u2( QCString("/home/dfaure/") ); + printf("\n* URL is %s\n",u2.url().ascii()); +// not ignoring trailing slash + check("KURL::directory(false,false)", u2.directory(false,false), "/home/dfaure/"); + check("KURL::directory(true,false)", u2.directory(true,false), "/home/dfaure"); +// ignoring trailing slash + check("KURL::directory(false,true)", u2.directory(false,true), "/home/"); + check("KURL::directory(true,true)", u2.directory(true,true), "/home"); + u2.cd(".."); + check("KURL::cd(\"..\")", u2.url(), "file:/home"); + u2.cd("thomas"); + check("KURL::cd(\"thomas\")", u2.url(), "file:/home/thomas"); + u2.cd("/opt/kde/bin/"); + check("KURL::cd(\"/opt/kde/bin/\")", u2.url(), "file:/opt/kde/bin/"); + u2 = "ftp://ftp.kde.org/"; + printf("\n* URL is %s\n",u2.url().ascii()); + u2.cd("pub"); + check("KURL::cd(\"pub\")", u2.url(), "ftp://ftp.kde.org/pub"); + u2 = u2.upURL(); + check("KURL::upURL()", u2.url(), "ftp://ftp.kde.org/"); + u2 = u1; + printf("\n* URL is %s\n",u2.url().ascii()); +// setFileName + u2.setFileName( "myfile.txt" ); + check("KURL::setFileName()", u2.url(), "file:/home/dfaure/myfile.txt"); + u2.setFileName( "myotherfile.txt" ); + check("KURL::setFileName()", u2.url(), "file:/home/dfaure/myotherfile.txt"); +// more tricky, renaming a directory (kpropsdlg.cc, line ~ 238) + QString tmpurl = "file:/home/dfaure/myolddir/"; + if ( tmpurl.at(tmpurl.length() - 1) == '/') +// It's a directory, so strip the trailing slash first + tmpurl.truncate( tmpurl.length() - 1); + KURL newUrl = tmpurl; + newUrl.setFileName( "mynewdir" ); + check("KURL::setFileName() special", newUrl.url(), "file:/home/dfaure/mynewdir"); +// addPath tests + newUrl.addPath( "subdir" ); + check("KURL::addPath(\"subdir\")", newUrl.url(), "file:/home/dfaure/mynewdir/subdir"); + newUrl.addPath( "/foo/" ); + check("KURL::addPath(\"/foo/\")", newUrl.url(), "file:/home/dfaure/mynewdir/subdir/foo/"); + u2 = "http://www.kde.org"; // no path + u2.addPath( "subdir" ); + check("KURL::addPath(\"subdir\")", u2.url(), "http://www.kde.org/subdir"); + u2.addPath( "" ); + check("KURL::addPath(\"subdir\")", u2.url(), "http://www.kde.org/subdir"); // unchanged + +// even more tricky + u2 = "print:/specials/Print%20To%20File%20(PDF%2FAcrobat)"; + printf("\n* URL is %s\n",u2.url().ascii()); + check("KURL::path()", u2.path(), "/specials/Print To File (PDF/Acrobat)"); + check("KURL::fileName()", u2.fileName(), "Print To File (PDF/Acrobat)"); + u2.setFileName( "" ); + check("KURL::setFileName()", u2.url(), "print:/specials/"); + + u2 = "file:/specials/Print"; + printf("\n* URL is %s\n",u2.url().ascii()); + check("KURL::path()", u2.path(), "/specials/Print"); + check("KURL::fileName()", u2.fileName(), "Print"); + u2.setFileName( "" ); + check("KURL::setFileName()", u2.url(), "file:/specials/"); + + const char * u3 = "ftp://host/dir1/dir2/myfile.txt"; + printf("\n* URL is %s\n",u3); + check("KURL::hasSubURL()", KURL(u3).hasSubURL() ? "yes" : "no", "no"); + lst.clear(); + lst = KURL::split( KURL(u3) ); + check("KURL::split()", lst.count()==1 ? "1" : "error", "1"); + check("KURL::split()", lst.first().url(), "ftp://host/dir1/dir2/myfile.txt"); +// cdUp code + KURL lastUrl = lst.last(); + QString dir = lastUrl.directory( true, true ); + check( "KURL::directory(true,true)", dir, "/dir1/dir2"); +*/ + + { + // !!! FAILS +// QString ucmp1 = "ftp://ftp.de.kde.org/dir"; +// QString ucmp2 = "ftp://ftp.de.kde.org/dir/"; +// QVERIFY(QUrl(ucmp1) == QUrl(ucmp2)); + } + + + /* +/// Comparisons + QString ucmp1 = "ftp://ftp.de.kde.org/dir"; + QString ucmp2 = "ftp://ftp.de.kde.org/dir/"; + check("urlcmp(only slash difference)", urlcmp(ucmp1,ucmp2)?"ko":"ok","ok"); + check("urlcmp(only slash difference, ignore_trailing)", urlcmp(ucmp1,ucmp2,true,false)?"ok":"ko","ok"); + QString ucmp3 = "ftp://ftp.de.kde.org/dir/#"; + check("urlcmp(only hash difference)", urlcmp(ucmp2,ucmp3)?"ko":"ok","ok"); + check("urlcmp(only hash difference, ignore_ref)", urlcmp(ucmp2,ucmp3,false,true)?"ok":"ko","ok"); + check("urlcmp(slash and hash difference, ignore_trailing, ignore_ref)", urlcmp(ucmp2,ucmp3,true,true)?"ok":"ko","ok"); + check("urlcmp(empty, empty)", urlcmp("","",false,true)?"ok":"ko","ok"); + check("urlcmp(empty, empty)", urlcmp("","")?"ok":"ko","ok"); + check("urlcmp(empty, not empty)", urlcmp("",ucmp1)?"ok":"ko","ko"); + check("urlcmp(empty, not empty)", urlcmp("",ucmp1,false,true)?"ok":"ko","ko"); + check("urlcmp(malformed, not empty)", urlcmp("file",ucmp1)?"ok":"ko","ko"); + check("urlcmp(malformed, not empty)", urlcmp("file",ucmp1,false,true)?"ok":"ko","ko"); + + KURL ftpUrl ( "ftp://ftp.de.kde.org" ); + printf("\n* URL is %s\n",ftpUrl.url().latin1()); + check("KURL::path()", ftpUrl.path(), QString()); + ftpUrl = "ftp://ftp.de.kde.org/"; + check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp.de.kde.org/host/subdir/") ? "yes" : "no", "yes"); + ftpUrl = "ftp://ftp/host/subdir/"; + check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir/") ? "yes" : "no", "yes"); + check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir") ? "yes" : "no", "yes"); + check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdi") ? "yes" : "no", "no"); + check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir/blah/") ? "yes" : "no", "yes"); + check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/blah/subdir") ? "yes" : "no", "no"); + check("KURL::isParentOf()", ftpUrl.isParentOf( "file://ftp/host/subdir/") ? "yes" : "no", "no"); + check("KURL::isParentOf()", ftpUrl.isParentOf( "ftp://ftp/host/subdir/subsub") ? "yes" : "no", "yes"); + +// WABA: The following tests are to test the handling of relative URLs as +// found on web-pages. + + KURL waba1( "http://www.website.com/directory/?hello#ref" ); + { + KURL waba2( waba1, "relative.html"); + check("http: Relative URL, single file", waba2.url(), "http://www.website.com/directory/relative.html"); + } + { + KURL waba2( waba1, "../relative.html"); + check("http: Relative URL, single file, directory up", waba2.url(), "http://www.website.com/relative.html"); + } + { + KURL waba2( waba1, "down/relative.html"); + check("http: Relative URL, single file, directory down", waba2.url(), "http://www.website.com/directory/down/relative.html"); + } + { + KURL waba2( waba1, "/down/relative.html"); + check("http: Relative URL, full path", waba2.url(), "http://www.website.com/down/relative.html"); + } + { + KURL waba2( waba1, "//www.kde.org/relative.html"); + check("http: Relative URL, with host", waba2.url(), "http://www.kde.org/relative.html"); + } + { + KURL waba2( waba1, "relative.html?query=test&name=harry"); + check("http: Relative URL, with query", waba2.url(), "http://www.website.com/directory/relative.html?query=test&name=harry"); + waba2.removeQueryItem("query"); + check("http: Removing query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry"); + waba2.addQueryItem("age", "18"); + check("http: Adding query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry&age=18"); + waba2.addQueryItem("age", "21"); + check("http: Adding query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry&age=18&age=21"); + waba2.addQueryItem("fullname", "Harry Potter"); + check("http: Adding query item", waba2.url(), "http://www.website.com/directory/relative.html?name=harry&age=18&age=21&fullname=Harry%20Potter"); + } + { + KURL waba2( waba1, "?query=test&name=harry"); + check("http: Relative URL, with query and no filename", waba2.url(), "http://www.website.com/directory/?query=test&name=harry"); + } + { + KURL waba2( waba1, "relative.html#with_reference"); + check("http: Relative URL, with reference", waba2.url(), "http://www.website.com/directory/relative.html#with_reference"); + } + { + KURL waba2( waba1, "#"); + check("http: Relative URL, with empty reference", waba2.url(), "http://www.website.com/directory/?hello#"); + } + { + KURL waba2( waba1, ""); + check("http: Empty relative URL", waba2.url(), "http://www.website.com/directory/?hello#ref"); + } + { + KURL base( "http://faure@www.kde.org" ); // no path + KURL waba2( base, "filename.html"); + check("http: Relative URL, orig URL had no path", waba2.url(), "http://faure@www.kde.org/filename.html"); + } + { + KURL base( "http://faure:pass@www.kde.org:81?query" ); + KURL rel1( base, "http://www.kde.org/bleh/"); // same host + check("http: Relative URL, orig URL had username", rel1.url(), "http://faure:pass@www.kde.org/bleh/"); + KURL rel2( base, "http://www.yahoo.org"); // different host + check("http: Relative URL, orig URL had username", rel2.url(), "http://www.yahoo.org"); + } + + waba1 = "http://www.website.com/directory/filename?bla#blub"; + { + KURL waba2( waba1, "relative.html"); + check("http: Relative URL, single file", waba2.url(), "http://www.website.com/directory/relative.html"); + } + { + KURL waba2( waba1, "../relative.html"); + check("http: Relative URL, single file, directory up", waba2.url(), "http://www.website.com/relative.html"); + } + { + KURL waba2( waba1, "down/relative.html"); + check("http: Relative URL, single file, directory down", waba2.url(), "http://www.website.com/directory/down/relative.html"); + } + { + KURL waba2( waba1, "/down/relative.html"); + check("http: Relative URL, full path", waba2.url(), "http://www.website.com/down/relative.html"); + } + { + KURL waba2( waba1, "relative.html?query=test&name=harry"); + check("http: Relative URL, with query", waba2.url(), "http://www.website.com/directory/relative.html?query=test&name=harry"); + } + { + KURL waba2( waba1, "?query=test&name=harry"); + check("http: Relative URL, with query and no filename", waba2.url(), "http://www.website.com/directory/filename?query=test&name=harry"); + } + { + KURL waba2( waba1, "relative.html#with_reference"); + check("http: Relative URL, with reference", waba2.url(), "http://www.website.com/directory/relative.html#with_reference"); + } + { + KURL waba2( waba1, "http:/relative.html"); // "rfc 1606 loophole" + check("http: Strange relative URL", waba2.url(), "http://www.website.com/relative.html"); + } + waba1.setUser("waldo"); + check("http: Set user", waba1.url(), "http://waldo@www.website.com/directory/filename?bla#blub"); + waba1.setUser("waldo/bastian"); + check("http: Set user with slash in it", waba1.url(), "http://waldo%2Fbastian@www.website.com/directory/filename?bla#blub"); + waba1.setRef( QString() ); + waba1.setPass( "pass" ); + waba1.setDirectory( "/foo" ); + waba1.setProtocol( "https" ); + waba1.setHost( "web.com" ); + waba1.setPort( 881 ); + check("http: setRef/setPass/setDirectory/setHost/setPort", waba1.url(), "https://waldo%2Fbastian:pass@web.com:881/foo/?bla"); + waba1.setDirectory( "/foo/" ); + check("http: setDirectory #2", waba1.url(), "https://waldo%2Fbastian:pass@web.com:881/foo/?bla"); + +// Empty queries should be preserved! + waba1 = "http://www.kde.org/cgi/test.cgi?"; + check("http: URL with empty query string", waba1.url(), + "http://www.kde.org/cgi/test.cgi?"); + +// Empty references should be preserved + waba1 = "http://www.kde.org/cgi/test.cgi#"; + check("http: URL with empty reference string", waba1.url(), + "http://www.kde.org/cgi/test.cgi#"); + check("hasRef()", waba1.hasRef()?"true":"false","true"); + check("hasHTMLRef()", waba1.hasHTMLRef()?"true":"false","true"); + check("encodedHtmlRef()", waba1.encodedHtmlRef(),QString()); + +// URLs who forgot to encode spaces in the query. + waba1 = "http://www.kde.org/cgi/test.cgi?hello=My Value"; + check("http: URL with incorrect encoded query", waba1.url(), + "http://www.kde.org/cgi/test.cgi?hello=My%20Value"); + +// URL with ':' in query (':' should NOT be encoded!) + waba1.setQuery("hello:My Value"); + check("http: URL with ':' in query", waba1.url(), + "http://www.kde.org/cgi/test.cgi?hello:My%20Value"); + check("upURL() removes query", waba1.upURL().url(), + "http://www.kde.org/cgi/test.cgi"); + +// URLs who forgot to encode spaces in the query. + waba1 = "http://www.kde.org/cgi/test.cgi?hello=My Value+20"; + check("http: URL with incorrect encoded query", waba1.url(), + "http://www.kde.org/cgi/test.cgi?hello=My%20Value+20"); + +// Urls without path (BR21387) + waba1 = "http://meine.db24.de?link=home_c_login_login"; + check("http: URL with empty path string", waba1.url(), + "http://meine.db24.de?link=home_c_login_login"); + check("http: URL with empty path string path", waba1.path(), + ""); + check("http: URL with empty path string query", waba1.query(), + "?link=home_c_login_login"); + + waba1 = "http://a:389?b=c"; + check( "http: URL with port, query, and empty path; url", waba1.url(), "http://a:389?b=c" ); + check( "http: URL with port, query, and empty path; host", waba1.host(), "a" ); + check( "http: URL with port, query, and empty path; port", QString::number( waba1.port() ), "389" ); + check( "http: URL with port, query, and empty path; path", waba1.path(), "" ); + check( "http: URL with port, query, and empty path; query", waba1.query(), "?b=c" ); + +// Urls without path (BR21387) + waba1 = "http://meine.db24.de#link=home_c_login_login"; + check("http: URL with empty path string", waba1.url(), + "http://meine.db24.de#link=home_c_login_login"); + check("http: URL with empty path string path", waba1.path(), + ""); + + waba1 = "http://a:389#b=c"; + check( "http: URL with port, ref, and empty path; url", waba1.url(), "http://a:389#b=c" ); + check( "http: URL with port, ref, and empty path; host", waba1.host(), "a" ); + check( "http: URL with port, ref, and empty path; port", QString::number( waba1.port() ), "389" ); + check( "http: URL with port, ref, and empty path; path", waba1.path(), "" ); + check( "http: URL with port, ref, and empty path; ref", waba1.ref(), "b=c" ); + check( "http: URL with port, ref, and empty path; query", waba1.query(), "" ); + +// IPV6 + waba1 = "http://[::FFFF:129.144.52.38]:81/index.html"; + check("http: IPV6 host", waba1.host(), + "::ffff:129.144.52.38"); + check("http: IPV6 port", QString("%1").arg(waba1.port()), + "81"); + +// IPV6 + waba1 = "http://waba:pass@[::FFFF:129.144.52.38]:81/index.html"; + check("http: IPV6 host", waba1.host(), + "::ffff:129.144.52.38"); + check("http: IPV6 host", waba1.user(), + "waba"); + check("http: IPV6 host", waba1.pass(), + "pass"); + check("http: IPV6 port", QString("%1").arg(waba1.port()), + "81"); + +// IPV6 + waba1 = "http://www.kde.org/cgi/test.cgi"; + waba1.setHost("::ffff:129.144.52.38"); + check("http: IPV6 host", waba1.url(), + "http://[::ffff:129.144.52.38]/cgi/test.cgi"); + waba1 = "http://[::ffff:129.144.52.38]/cgi/test.cgi"; + assert( waba1.isValid() ); + +// IPV6 without path + waba1 = "http://[::ffff:129.144.52.38]?query"; + assert( waba1.isValid() ); + check("http: IPV6 without path", waba1.url(), + "http://[::ffff:129.144.52.38]?query"); + check("http: IPV6 without path; query", waba1.query(), + "?query"); + waba1 = "http://[::ffff:129.144.52.38]#ref"; + assert( waba1.isValid() ); + check("http: IPV6 without path", waba1.url(), + "http://[::ffff:129.144.52.38]#ref"); + check("http: IPV6 without path; ref", waba1.ref(), + "ref"); +// IPV6 without path but with a port + waba1 = "http://[::ffff:129.144.52.38]:81?query"; + assert( waba1.isValid() ); + check("http: IPV6 without path", waba1.url(), + "http://[::ffff:129.144.52.38]:81?query"); + check("http: IPV6 without path; port", QString::number( waba1.port() ), "81" ); + check("http: IPV6 without path; query", waba1.query(), "?query"); + waba1 = "http://[::ffff:129.144.52.38]:81#ref"; + assert( waba1.isValid() ); + check("http: IPV6 without path", waba1.url(), + "http://[::ffff:129.144.52.38]:81#ref"); + check("http: IPV6 without path; port", QString::number( waba1.port() ), "81" ); + check("http: IPV6 without path; ref", waba1.ref(), "ref"); + +// Streaming operators + KURL origURL( "http://www.website.com/directory/?#ref" ); + waba1 = "http://[::ffff:129.144.52.38]:81?query"; + QByteArray buffer; + { + QDataStream stream( buffer, QIODevice::WriteOnly ); + stream << origURL + << KURL( "file:" ) // an invalid one + << waba1; // the IPv6 one + } + { + QDataStream stream( buffer, QIODevice::ReadOnly ); + KURL restoredURL; + stream >> restoredURL; + check( "Streaming valid URL", origURL.url(), restoredURL.url() ); + stream >> restoredURL; + check( "Streaming invalid URL", restoredURL.isValid()?"valid":"malformed", "malformed" ); + check( "Streaming invalid URL", restoredURL.url(), "file:" ); + stream >> restoredURL; + check( "Streaming ipv6 URL with query", restoredURL.url(), waba1.url() ); + } + +// Broken stuff + waba1 = "file:a"; + check("Broken stuff #1 path", waba1.path(), "a"); + check("Broken stuff #1 fileName(false)", waba1.fileName(false), "a"); + check("Broken stuff #1 fileName(true)", waba1.fileName(true), "a"); + check("Broken stuff #1 directory(false, false)", waba1.directory(false, false), ""); + check("Broken stuff #1 directory(true, false)", waba1.directory(true, false), ""); + check("Broken stuff #1 directory(false, true)", waba1.directory(true, true), ""); + + waba1 = "file:a/"; + check("Broken stuff #2 path", waba1.path(), "a/"); + check("Broken stuff #2 fileName(false)", waba1.fileName(false), ""); + check("Broken stuff #2 fileName(true)", waba1.fileName(true), "a"); + check("Broken stuff #2 directory(false, false)", waba1.directory(false, false), "a/"); + check("Broken stuff #2 directory(true, false)", waba1.directory(true, false), "a"); + check("Broken stuff #2 directory(false, true)", waba1.directory(true, true), ""); + + waba1 = "file:"; + check("Broken stuff #3 empty", waba1.isEmpty()?"EMPTY":"NOT", "NOT"); + check("Broken stuff #3 valid", waba1.isValid()?"VALID":"MALFORMED", "MALFORMED"); + check("Broken stuff #3 path", waba1.path(), ""); + check("Broken stuff #3 fileName(false)", waba1.fileName(false), ""); + check("Broken stuff #3 fileName(true)", waba1.fileName(true), ""); + check("Broken stuff #3 directory(false, false)", waba1.directory(false, false), ""); + check("Broken stuff #3 directory(true, false)", waba1.directory(true, false), ""); + check("Broken stuff #3 directory(false, true)", waba1.directory(true, true), ""); + KURL broken; + broken.setPath( QString() ); + check("Broken stuff #4 empty", broken.isEmpty()?"EMPTY":"NOT", "NOT"); +// It's valid: because isValid refers to parsing, not to what happens afterwards. + check("Broken stuff #4 valid", broken.isValid()?"VALID":"MALFORMED", "VALID"); + check("Broken stuff #4 path", broken.path(), ""); + broken = "file://"; // just because coolo wondered + check("Broken stuff #5 empty", broken.isEmpty()?"EMPTY":"NOT", "NOT"); + check("Broken stuff #5 valid", broken.isValid()?"VALID":"MALFORMED", "MALFORMED"); + check("Broken stuff #5 path", broken.path(), ""); + broken = "file"; + check("Broken stuff #6 valid", broken.isValid()?"VALID":"MALFORMED", "MALFORMED"); + +#if 0 // BROKEN? +// UNC like names + KURL unc1("FILE://localhost/home/root"); + check("UNC, with localhost", unc1.path(), "/home/root"); + check("UNC, with localhost", unc1.url(), "file:/home/root"); +#endif + KURL unc2("file:///home/root"); + check("UNC, with empty host", unc2.path(), "/home/root"); + check("UNC, with empty host", unc2.url(), "file:/home/root"); + + { + KURL unc3("FILE://remotehost/home/root"); +#if 0 // BROKEN? + check("UNC, with remote host", unc3.path(), "//remotehost/home/root"); +#endif + check("UNC, with remote host", unc3.url(), "file://remotehost/home/root"); + KURL url2("file://atlas/dfaure"); + check("KURL::host()", url2.host(), "atlas"); + check("KURL::path()", url2.path(), "/dfaure"); + //check("KURL::path()", url3.path(), "//atlas/dfaure"); // says Waba + //KURL url3("file:////atlas/dfaure"); + //check("KURL::path()", url3.path(), "//atlas/dfaure"); // says Waba + } + + KURL umail1 ( "mailto:faure@kde.org" ); + check("mailto: URL, general form", umail1.protocol(), "mailto"); + check("mailto: URL, general form", umail1.path(), "faure@kde.org"); + check("mailto: URL, is relative", KURL::isRelativeURL("mailto:faure@kde.org") ? "true" : "false", "false"); + KURL umail2 ( "mailto:Faure David <faure@kde.org>" ); + check("mailto: URL, general form", umail2.protocol(), "mailto"); + check("mailto: URL, general form", umail2.path(), "Faure David <faure@kde.org>"); + check("isRelativeURL(\"mailto:faure@kde.org\")", KURL::isRelativeURL("mailto:faure@kde.org") ? "yes" : "no", "no"); + KURL umail3 ( "mailto:" ); + check("mailto: invalid URL", umail3.isValid()?"valid":"malformed", "malformed"); + + check("man: URL, is relative", KURL::isRelativeURL("man:mmap") ? "true" : "false", "false"); + check("javascript: URL, is relative", KURL::isRelativeURL("javascript:doSomething()") ? "true" : "false", "false"); +// more isRelative + check("file: URL, is relative", KURL::isRelativeURL("file:/blah") ? "true" : "false", "false"); + check("/path, is relative", KURL::isRelativeURL("/path") ? "true" : "false", "true"); // arguable + check("something, is relative", KURL::isRelativeURL("something") ? "true" : "false", "true"); + KURL about("about:konqueror"); + check("about:",about.path(),"konqueror"); + + KURL ulong("https://swww.gad.de:443/servlet/CookieAccepted?MAIL=s@gad.de&VER=25901"); + check("host",ulong.host(),"swww.gad.de"); + check("path",ulong.path(),"/servlet/CookieAccepted"); + + QTextCodec::setCodecForLocale( KGlobal::charsets()->codecForName( "iso-8859-1" ) ); +// UTF8 tests + KURL uloc("/home/dfaure/konqtests/Matériel"); + check("locale8bit",uloc.url().latin1(),"file:/home/dfaure/konqtests/Mat%E9riel"); // escaping the letter would be correct too + check("pretty",uloc.prettyURL(),"file:/home/dfaure/konqtests/Matériel"); // escaping the letter would be correct too +// 106 is MIB for UTF-8 + check("UTF8",uloc.url(0, 106),"file:/home/dfaure/konqtests/Mat%C3%A9riel"); + uloc = KURL("file:/home/dfaure/konqtests/Mat%C3%A9riel", 106); + check("UTF8 path", uloc.path(), "/home/dfaure/konqtests/Matériel"); + +// fromPathOrURL tests + uloc = KURL::fromPathOrURL( "/home/dfaure/konqtests/Mat%E9riel" ); + check("fromPathOrURL path", uloc.path(), "/home/dfaure/konqtests/Mat%E9riel"); + uloc = KURL::fromPathOrURL( "http://www.kde.org" ); + check("fromPathOrURL url", uloc.url(), "http://www.kde.org"); + uloc = KURL::fromPathOrURL( "www.kde.org" ); + check("fromPathOrURL url", uloc.isValid()?"valid":"malformed", "malformed"); + uloc = KURL::fromPathOrURL( "index.html" ); + check("fromPathOrURL url", uloc.isValid()?"valid":"malformed", "malformed"); + uloc = KURL::fromPathOrURL( "" ); + check("fromPathOrURL url", uloc.isValid()?"valid":"malformed", "malformed"); + + QTextCodec::setCodecForLocale( KGlobal::charsets()->codecForName( "koi8-r" ) ); + baseURL = "file:/home/coolo"; + KURL russian = baseURL.directory(false, true) + QString::fromLocal8Bit( "ÆÇÎ7" ); + check( "russian", russian.url(), "file:/home/%C6%C7%CE7" ); + + KURL tobi1("http://some.host.net/path/to/file#fragmentPrecedes?theQuery"); + check("wrong order of query and hypertext reference #1", tobi1.ref(), "fragmentPrecedes"); + check("wrong order of query and hypertext reference #2", tobi1.query(), "?theQuery"); + + tobi1 = "http://host.net/path/?#http://brokenäadsfküpoij31ü029muß2890zupycÜ*!*'OŽ+ß0i"; + check("zero-length query",tobi1.query(),"?"); + + tobi1 = "http://host.net/path/#no-query"; + check("no query", tobi1.query(),""); + + tobi1 = "http://host.net/path?myfirstquery#andsomeReference"; + tobi1.setEncodedPathAndQuery("another/path/?another&query"); + check("setEncodedPathAndQuery test#1", tobi1.query(), "?another&query"); + check("setEncodedPathAndQuery test#2", tobi1.path(), "another/path/"); + tobi1.setEncodedPathAndQuery("another/path?another&query"); + check("setEncodedPathAndQuery test#1", tobi1.query(), "?another&query"); + check("setEncodedPathAndQuery test#2", tobi1.path(), "another/path"); + + KURL theKow = "http://www.google.de/search?q=frerich&hlx=xx&hl=de&empty=&lr=lang+de&test=%2B%20%3A%25"; + check("queryItem (first item)", theKow.queryItem("q"), "frerich"); + check("queryItem (middle item)", theKow.queryItem("hl"), "de"); + check("queryItem (last item)", theKow.queryItem("lr"), "lang de"); + check("queryItem (invalid item)", theKow.queryItem("InterstellarCounselor"), QString()); + check("queryItem (empty item)", theKow.queryItem("empty"), ""); + check("queryItem (item with encoded chars)", theKow.queryItem("test"), "+ :%"); + +// checks for queryItems(), which returns a QMap<QString,QString>: + KURL queryUrl( "mailto:Marc%20Mutz%20%3cmutz@kde.org%3E?" + "Subject=subscribe+me&" + "body=subscribe+mutz%40kde.org&" + "Cc=majordomo%40lists.kde.org" ); + check("queryItems (c.s. keys)", + QStringList(queryUrl.queryItems().keys()).join(", "), + "Cc, Subject, body" ); + check("queryItems (c.i.s. keys)", + QStringList(queryUrl.queryItems(KURL::CaseInsensitiveKeys).keys()).join(", "), + "body, cc, subject" ); + check("queryItems (values; c.s. keys)", + QStringList(queryUrl.queryItems().values()).join(", "), + "majordomo@lists.kde.org, subscribe me, subscribe mutz@kde.org" ); + check("queryItems (values; c.i.s. keys)", + QStringList(queryUrl.queryItems(KURL::CaseInsensitiveKeys).values()).join(", "), + "subscribe mutz@kde.org, majordomo@lists.kde.org, subscribe me" ); + + KURL umlaut1("http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel"); + check("umlaut1.url()", umlaut1.url(), "http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel"); + + KURL umlaut2("http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel", 106); + check("umlaut2.url()", umlaut2.url(), "http://www.clever-tanken.de/liste.asp?ort=N%FCrnberg&typ=Diesel"); + +// Needed for #49616 + check( "encode_string('C++')", KURL::encode_string( "C++" ), "C%2B%2B" ); + check( "decode_string('C%2B%2B')", KURL::decode_string( "C%2B%2B" ), "C++" ); + check( "decode_string('C%00A')", KURL::decode_string( "C%00%A" ), "C" ); // we stop at %00 + + check( "encode_string('%')", KURL::encode_string( "%" ), "%25" ); + check( "encode_string(':')", KURL::encode_string( ":" ), "%3A" ); + + KURL amantia( "http://%E1.foo" ); + check("amantia.isValid()", amantia.isValid() ? "true" : "false", "true"); +#ifdef HAVE_IDNA_H + check("amantia.url()", amantia.url(), "http://xn--80a.foo"); // Non-ascii is allowed in IDN domain names. +#else + check("amantia.url()", amantia.url(), "http://?.foo"); // why not +#endif + + KURL smb("smb://domain;username:password@server/share"); + check("smb.isValid()", smb.isValid() ? "true" : "false", "true"); + check("smb.user()", smb.user(), "domain;username"); + smb = "smb:/"; + check("smb:/", smb.isValid()?"VALID":"MALFORMED", "VALID"); + smb = "smb://"; // kurl.cpp rev 1.106 + check("smb://", smb.isValid()?"VALID":"MALFORMED", "MALFORMED"); + smb = "smb://host"; + check("smb://host", smb.isValid()?"VALID":"MALFORMED", "VALID"); + smb = "smb:///"; + check("smb:///", smb.isValid()?"VALID":"MALFORMED", "VALID"); + + KURL weird; + weird = "http://strange<hostname>/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "false"); + + weird = "http://strange<username>@strange<hostname>/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "false"); + + weird = "http://strange<username>@ok_hostname/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "true"); + check("weird.host()", weird.host(), "ok_hostname"); + + weird = "http://strange;hostname/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "false"); + + weird = "http://strange;username@strange;hostname/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "false"); + + weird = "http://strange;username@ok_hostname/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "true"); + check("weird.host()", weird.host(), "ok_hostname"); + + weird = "http://strange;username:password@strange;hostname/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "false"); + + weird = "http://strange;username:password@ok_hostname/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "true"); + check("weird.host()", weird.host(), "ok_hostname"); + + weird = "http://[strange;hostname]/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "false"); + + weird = "http://[::fff:1:23]/"; + check("weird.isValid()", weird.isValid() ? "true" : "false", "true"); + check("weird.host()", weird.host(), "::fff:1:23"); + + KURL com1("http://server.com/dir/", "."); + check("com1.url()", com1.url(), "http://server.com/dir/"); + + KURL com2("http://server.com/dir/blubb/", "blah/"); + check("com2.url()", com2.url(), "http://server.com/dir/blubb/blah/"); + + KURL utf8_1("audiocd:/By%20Name/15%20Geantra%C3%AE.wav", 106); + check("utf8_1.fileName()", utf8_1.fileName(), QString::fromLatin1("15 Geantraî.wav")); + + KURL utf8_2("audiocd:/By%20Name/15%2fGeantra%C3%AE.wav", 106); + check("utf8_2.fileName()", utf8_2.fileName(), QString::fromLatin1("15/Geantraî.wav")); + + KURL url_newline_1("http://www.foo.bar/foo/bar\ngnork"); + check("url_newline_1.url()", url_newline_1.url(), QString::fromLatin1("http://www.foo.bar/foo/bar%0Agnork")); + + KURL url_newline_2("http://www.foo.bar/foo?bar\ngnork"); + check("url_newline_2.url()", url_newline_2.url(), QString::fromLatin1("http://www.foo.bar/foo?bar%0Agnork")); + + KURL local_file_1("file://localhost/my/file"); + check("local_file_1.isLocalFile()", local_file_1.isLocalFile() ? "true" : "false", "true"); + + KURL local_file_2("file://www.kde.org/my/file"); + check("local_file_2.isLocalFile()", local_file_2.isLocalFile() ? "true" : "false", "false"); + + KURL local_file_3; + local_file_3.setHost(getenv("HOSTNAME")); + local_file_3.setPath("/my/file"); + printf("\nURL=%s\n", local_file_3.url().latin1()); + check("local_file_3.isLocalFile()", local_file_3.isLocalFile() ? "true" : "false", "true"); + + KURL local_file_4("file:///my/file"); + check("local_file_4.isLocalFile()", local_file_4.isLocalFile() ? "true" : "false", "true"); + + KURL local_file_5; + local_file_5.setPath("/foo?bar"); + check("local_file_5.url()", local_file_5.url(), "file:/foo%3Fbar"); + + QString basePath = "/home/bastian"; + + check("relativePath(\"/home/bastian\", \"/home/bastian\")", KURL::relativePath(basePath, "/home/bastian"), "./"); + bool b; + check("relativePath(\"/home/bastian\", \"/home/bastian/src/plugins\")", KURL::relativePath(basePath, "/home/bastian/src/plugins", &b), "./src/plugins"); + check("Is a subdirectory?", b ? "true" : "false", "true"); + check("relativePath(\"/home/bastian\", \"./src/plugins\")", KURL::relativePath(basePath, "./src/plugins"), "./src/plugins"); + check("relativePath(\"/home/bastian\", \"/home/waba/src/plugins\")", KURL::relativePath(basePath, "/home/waba/src/plugins", &b), "../waba/src/plugins"); + check("Is a subdirectory?", b ? "true" : "false", "false"); + check("relativePath(\"/home/bastian\", \"/\")", KURL::relativePath(basePath, "/"), "../../"); + + check("relativePath(\"/\", \"/\")", KURL::relativePath("/", "/"), "./"); + check("relativePath(\"/\", \"/home/bastian\")", KURL::relativePath("/", "/home/bastian"), "./home/bastian"); + check("relativePath(\"\", \"/home/bastian\")", KURL::relativePath("", "/home/bastian"), "/home/bastian"); + + baseURL = "http://www.kde.org/index.html"; + check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/index.html#help\")", KURL::relativeURL(baseURL, "http://www.kde.org/index.html#help"), "#help"); + check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/index.html?help=true\")", KURL::relativeURL(baseURL, "http://www.kde.org/index.html?help=true"), "index.html?help=true"); + check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/contact.html\")", KURL::relativeURL(baseURL, "http://www.kde.org/contact.html"), "contact.html"); + check("relativeURL(\"http://www.kde.org/index.html\", \"ftp://ftp.kde.org/pub/kde\")", KURL::relativeURL(baseURL, "ftp://ftp.kde.org/pub/kde"), "ftp://ftp.kde.org/pub/kde"); + check("relativeURL(\"http://www.kde.org/index.html\", \"http://www.kde.org/index.html\")", KURL::relativeURL(baseURL, "http://www.kde.org/index.html"), "./"); + + baseURL = "http://www.kde.org/info/index.html"; + check("relativeURL(\"http://www.kde.org/info/index.html\", \"http://www.kde.org/bugs/contact.html\")", KURL::relativeURL(baseURL, "http://www.kde.org/bugs/contact.html"), "../bugs/contact.html"); + + baseURL = "ptal://mlc:usb:PC_970"; + check("isValid()?", baseURL.isValid() ? "true" : "false", "false"); + check("url()", baseURL.url(), "ptal://mlc:usb:PC_970"); + + baseURL = "http://mlc:80/"; + check("isValid()?", baseURL.isValid() ? "true" : "false", "true"); + check("port()?", QString::number(baseURL.port()), "80"); + check("path()?", baseURL.path(), "/"); + + baseURL = "ptal://mlc:usb@PC_970"; // User=mlc, password=usb, host=PC_970 + check("isValid()?", baseURL.isValid() ? "true" : "false", "true"); + check("host()?", baseURL.host(), "pc_970"); + check("user()?", baseURL.user(), "mlc"); + check("pass()?", baseURL.pass(), "usb"); + + weird = "ftp://user%40host.com@ftp.host.com/var/www/"; + check("user()?", weird.user(), "user@host.com" ); + check("host()?", weird.host(), "ftp.host.com" ); + KURL up = weird.upURL(); + check("KURL::upURL()", up.url(), "ftp://user%40host.com@ftp.host.com/var/"); + up = up.upURL(); + check("KURL::upURL()", up.url(), "ftp://user%40host.com@ftp.host.com/"); + up = up.upURL(); + check("KURL::upURL()", up.url(), "ftp://user%40host.com@ftp.host.com/"); // unchanged + + KURL ldap = "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)"; + check("host()?", ldap.host(), "host.com"); + check("port()?", QString("%1").arg(ldap.port()), "6666"); + check("path()?", ldap.path(), "/o=University of Michigan,c=US"); + check("query()?", ldap.query(), "??sub?(cn=Babs%20Jensen)"); + check("url()?", ldap.url(), "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)"); + ldap.setQuery("??sub?(cn=Karl%20Marx)"); + check("query()?", ldap.query(), "??sub?(cn=Karl%20Marx)"); + check("url()?", ldap.url(), "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Karl%20Marx)"); + + KURL leo = "data:text/html,http://www.invalid/"; + check("data URL: isValid", leo.isValid()?"valid":"malformed", "valid" ); + check("data URL: protocol", leo.protocol(), "data" ); + check("data URL: url", leo.url(), "data:text/html,http://www.invalid/" ); + check("data URL: path", leo.path(), "text/html,http://www.invalid/" ); + +// URI Mode tests + url1 = "http://www.foobar.com/"; + check("KURL(\"http://www.foobar.com/\").uriMode()", QString::number(url1.uriMode()), QString::number(KURL::URL)); + url1 = "mailto:user@host.com"; + check("KURL(\"mailto:user@host.com\").uriMode()", QString::number(url1.uriMode()), QString::number(KURL::Mailto)); + check("KURL(\"mailto:user@host.com\").url()", url1.url(), "mailto:user@host.com"); + check("KURL(\"mailto:user@host.com\").url(0, 106)", url1.url(0, 106), "mailto:user@host.com"); + url1 = "data:text/plain,foobar?gazonk=flarp"; + check("KURL(\"data:text/plain,foobar?gazonk=flarp\").uriMode()", QString::number(url1.uriMode()), QString::number(KURL::RawURI)); + check("KURL(\"data:text/plain,foobar?gazonk=flarp\").path()", url1.path(), "text/plain,foobar?gazonk=flarp"); + url1 = "mailto:User@Host.COM?subject=Hello"; + check("KURL(\"mailto:User@Host.COM?subject=Hello\").path()", url1.path(), "User@host.com"); + + printf("\nTest OK !\n"); + */ + + + } + +void tst_QUrl::i18n_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QByteArray>("punyOutput"); + + QTest::newRow("øl") << QString::fromLatin1("http://ole:passord@www.øl.no/index.html?ole=æsemann&ilder gud=hei#top") + << QByteArray("http://ole:passord@www.xn--l-4ga.no/index.html?ole=%C3%A6semann&ilder%20gud=hei#top"); + QTest::newRow("räksmörgås") << QString::fromLatin1("http://www.räksmörgås.no/") + << QByteArray("http://www.xn--rksmrgs-5wao1o.no/"); + QTest::newRow("bühler") << QString::fromLatin1("http://www.bühler.no/") + << QByteArray("http://www.xn--bhler-kva.no/"); + QTest::newRow("non-latin1") + << QString::fromUtf8("http://www.\316\261\316\270\316\256\316\275\316\261.info") + << QByteArray("http://www.xn--jxafb0a0a.info"); +} + +void tst_QUrl::i18n() +{ + QFETCH(QString, input); + QFETCH(QByteArray, punyOutput); + + QUrl url(input); + QVERIFY(url.isValid()); + + QCOMPARE(url.toEncoded().constData(), punyOutput.constData()); + QCOMPARE(QUrl::fromEncoded(punyOutput), url); + QCOMPARE(QUrl::fromEncoded(punyOutput).toString(), input); +} + + +void tst_QUrl::resolving_data() +{ + QTest::addColumn<QString>("baseUrl"); + QTest::addColumn<QString>("relativeUrl"); + QTest::addColumn<QString>("relsolvedUrl"); + + // 5.4.1 Normal Examples (http://www.ietf.org/rfc/rfc3986.txt) + QTest::newRow("g:h") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g:h") << QString::fromLatin1("g:h"); + QTest::newRow("g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g") << QString::fromLatin1("http://a/b/c/g"); + QTest::newRow("./g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("./g") << QString::fromLatin1("http://a/b/c/g"); + QTest::newRow("g/") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g/") << QString::fromLatin1("http://a/b/c/g/"); + QTest::newRow("/g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("/g") << QString::fromLatin1("http://a/g"); + QTest::newRow("//g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("//g") << QString::fromLatin1("http://g"); + QTest::newRow("?y") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("?y") << QString::fromLatin1("http://a/b/c/d;p?y"); + QTest::newRow("g?y") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g?y") << QString::fromLatin1("http://a/b/c/g?y"); + QTest::newRow("#s") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("#s") << QString::fromLatin1("http://a/b/c/d;p?q#s"); + QTest::newRow("g#s") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g#s") << QString::fromLatin1("http://a/b/c/g#s"); + QTest::newRow("g?y#s") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g?y#s") << QString::fromLatin1("http://a/b/c/g?y#s"); + QTest::newRow(";x") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1(";x") << QString::fromLatin1("http://a/b/c/;x"); + QTest::newRow("g;x") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g;x") << QString::fromLatin1("http://a/b/c/g;x"); + QTest::newRow("g;x?y#s") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g;x?y#s") << QString::fromLatin1("http://a/b/c/g;x?y#s"); + QTest::newRow("[empty]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("") << QString::fromLatin1("http://a/b/c/d;p?q"); + QTest::newRow(".") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1(".") << QString::fromLatin1("http://a/b/c/"); + QTest::newRow("./") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("./") << QString::fromLatin1("http://a/b/c/"); + QTest::newRow("..") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("..") << QString::fromLatin1("http://a/b/"); + QTest::newRow("../") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../") << QString::fromLatin1("http://a/b/"); + QTest::newRow("../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../g") << QString::fromLatin1("http://a/b/g"); + QTest::newRow("../..") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../..") << QString::fromLatin1("http://a/"); + QTest::newRow("../../") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../") << QString::fromLatin1("http://a/"); + QTest::newRow("../../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../g") << QString::fromLatin1("http://a/g"); + + // 5.4.2 Abnormal Examples (http://www.ietf.org/rfc/rfc3986.txt) + + // Parsers must be careful in handling cases where there are more + // relative path ".." segments than there are hierarchical levels in the + // base URI's path. Note that the ".." syntax cannot be used to change + // the authority component of a URI. + QTest::newRow("../../../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../g") << QString::fromLatin1("http://a/g"); + QTest::newRow("../../../../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("../../../../g") << QString::fromLatin1("http://a/g"); + + // Similarly, parsers must remove the dot-segments "." and ".." when + // they are complete components of a path, but not when they are only + // part of a segment. + QTest::newRow("/./g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("/./g") << QString::fromLatin1("http://a/g"); + QTest::newRow("/../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("/../g") << QString::fromLatin1("http://a/g"); + QTest::newRow("g.") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g.") << QString::fromLatin1("http://a/b/c/g."); + QTest::newRow(".g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1(".g") << QString::fromLatin1("http://a/b/c/.g"); + QTest::newRow("g..") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g..") << QString::fromLatin1("http://a/b/c/g.."); + QTest::newRow("..g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("..g") << QString::fromLatin1("http://a/b/c/..g"); + + // Less likely are cases where the relative URI reference uses + // unnecessary or nonsensical forms of the "." and ".." complete path + // segments. + QTest::newRow("./../g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("./../g") << QString::fromLatin1("http://a/b/g"); + QTest::newRow("./g/.") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("./g/.") << QString::fromLatin1("http://a/b/c/g/"); + QTest::newRow("g/./h") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g/./h") << QString::fromLatin1("http://a/b/c/g/h"); + QTest::newRow("g/../h") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g/../h") << QString::fromLatin1("http://a/b/c/h"); + QTest::newRow("g;x=1/./y") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g;x=1/./y") << QString::fromLatin1("http://a/b/c/g;x=1/y"); + QTest::newRow("g;x=1/../y") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g;x=1/../y") << QString::fromLatin1("http://a/b/c/y"); + + // Some applications fail to separate the reference's query and/or + // fragment components from a relative path before merging it with the + // base path and removing dot-segments. This error is rarely noticed, + // since typical usage of a fragment never includes the hierarchy ("/") + // character, and the query component is not normally used within + // relative references. + QTest::newRow("g?y/./x") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g?y/./x") << QString::fromLatin1("http://a/b/c/g?y/./x"); + QTest::newRow("g?y/../x") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g?y/../x") << QString::fromLatin1("http://a/b/c/g?y/../x"); + QTest::newRow("g#s/./x") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g#s/./x") << QString::fromLatin1("http://a/b/c/g#s/./x"); + QTest::newRow("g#s/../x") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("g#s/../x") << QString::fromLatin1("http://a/b/c/g#s/../x"); + + // Some parsers allow the scheme name to be present in a relative URI + // reference if it is the same as the base URI scheme. This is + // considered to be a loophole in prior specifications of partial URI + // [RFC1630]. Its use should be avoided, but is allowed for backward + // compatibility. + // For strict parsers : +// QTest::newRow("http:g [for strict parsers]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("http:g") << QString::fromLatin1("http:g"); + // For backward compatibility : + QTest::newRow("http:g [for backward compatibility]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("http:g") << QString::fromLatin1("http://a/b/c/g"); + + // Resolve relative with relative + QTest::newRow("../a (1)") << QString::fromLatin1("b") << QString::fromLatin1("../a") << QString::fromLatin1("a"); + QTest::newRow("../a (2)") << QString::fromLatin1("b/a") << QString::fromLatin1("../a") << QString::fromLatin1("a"); + QTest::newRow("../a (3)") << QString::fromLatin1("b/c/a") << QString::fromLatin1("../a") << QString::fromLatin1("b/a"); + QTest::newRow("../a (4)") << QString::fromLatin1("b") << QString::fromLatin1("/a") << QString::fromLatin1("/a"); + + QTest::newRow("../a (5)") << QString::fromLatin1("/b") << QString::fromLatin1("../a") << QString::fromLatin1("/a"); + QTest::newRow("../a (6)") << QString::fromLatin1("/b/a") << QString::fromLatin1("../a") << QString::fromLatin1("/a"); + QTest::newRow("../a (7)") << QString::fromLatin1("/b/c/a") << QString::fromLatin1("../a") << QString::fromLatin1("/b/a"); + QTest::newRow("../a (8)") << QString::fromLatin1("/b") << QString::fromLatin1("/a") << QString::fromLatin1("/a"); +} + +void tst_QUrl::resolving() +{ + QFETCH(QString, baseUrl); + QFETCH(QString, relativeUrl); + QFETCH(QString, relsolvedUrl); + + QUrl url(baseUrl); + QCOMPARE(url.resolved(relativeUrl).toString(), relsolvedUrl); +} + + +void tst_QUrl::toString_data() +{ + QTest::addColumn<QString>("urlString"); + QTest::addColumn<uint>("options"); + QTest::addColumn<QString>("string"); + + QTest::newRow("data0") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme) + << QString::fromLatin1("//ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data2") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemovePassword) + << QString::fromLatin1("http://ole@www.troll.no:9090/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data3") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveUserInfo) + << QString::fromLatin1("http://www.troll.no:9090/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data4") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemovePort) + << QString::fromLatin1("http://ole:password@www.troll.no/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data5") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveAuthority) + << QString::fromLatin1("http:/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data6") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemovePath) + << QString::fromLatin1("http://ole:password@www.troll.no:9090?ole=semann&gud=hei#top"); + + QTest::newRow("data7") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveQuery) + << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html#top"); + + QTest::newRow("data8") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveFragment) + << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei"); + + QTest::newRow("data9") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme | QUrl::RemovePassword) + << QString::fromLatin1("//ole@www.troll.no:9090/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data10") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme | QUrl::RemoveUserInfo) + << QString::fromLatin1("//www.troll.no:9090/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data11") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme | QUrl::RemovePort) + << QString::fromLatin1("//ole:password@www.troll.no/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data12") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme | QUrl::RemoveAuthority) + << QString::fromLatin1("/index.html?ole=semann&gud=hei#top"); + + QTest::newRow("data13") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme | QUrl::RemovePath) + << QString::fromLatin1("//ole:password@www.troll.no:9090?ole=semann&gud=hei#top"); + + QTest::newRow("data14") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme | QUrl::RemoveAuthority | QUrl::RemoveFragment) + << QString::fromLatin1("/index.html?ole=semann&gud=hei"); + + QTest::newRow("data15") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveAuthority | QUrl::RemoveQuery) + << QString::fromLatin1("http:/index.html#top"); + + QTest::newRow("data16") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemovePassword | QUrl::RemovePort + | QUrl::RemovePath | QUrl::RemoveQuery + | QUrl::RemoveFragment) + << QString::fromLatin1("http://ole@www.troll.no"); + + QTest::newRow("data17") << QString::fromLatin1("http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top") + << uint(QUrl::RemoveScheme | QUrl::RemovePassword + | QUrl::RemovePort | QUrl::RemovePath + | QUrl::RemoveQuery | QUrl::RemoveFragment) + << QString::fromLatin1("//ole@www.troll.no"); + + QTest::newRow("data18") << QString::fromLatin1("http://andreas:hemmelig@www.vg.no/?my=query&your=query#yougotfragged") + << uint(QUrl::None) + << QString::fromLatin1("http://andreas:hemmelig@www.vg.no/?my=query&your=query#yougotfragged"); + + /* + QTest::newRow("data19") << QString::fromLatin1("http://andreas:hemmelig@www.vg.no/a/../?my=query&your=query#yougotfragged") + << uint(QUrl::None) + << QString::fromLatin1("http://andreas:hemmelig@www.vg.no/?my=query&your=query#yougotfragged"); + */ + + QTest::newRow("nopath_task31320") << QString::fromLatin1("host://protocol") + << uint(QUrl::None) + << QString::fromLatin1("host://protocol"); + + QTest::newRow("underscore_QTBUG-7434") << QString::fromLatin1("http://foo_bar.host.com/rss.php") + << uint(QUrl::None) + << QString::fromLatin1("http://foo_bar.host.com/rss.php"); +} + +void tst_QUrl::toString() +{ + QFETCH(QString, urlString); + QFETCH(uint, options); + QFETCH(QString, string); + + QUrl url(urlString); + QCOMPARE(url.toString(QUrl::FormattingOptions(options)), string); +} + +//### more tests ... what do we expect ... +void tst_QUrl::isParentOf_data() +{ + QTest::addColumn<QString>("parent"); + QTest::addColumn<QString>("child"); + QTest::addColumn<bool>("trueFalse"); + + QTest::newRow("data0") << QString::fromLatin1("http://a.b.c/d") + << QString::fromLatin1("http://a.b.c/d/e?f") << true; + QTest::newRow("data1") << QString::fromLatin1("http://a.b.c/d") + << QString::fromLatin1("http://a.b.c/d") << false; + QTest::newRow("data2") << QString::fromLatin1("http://a.b.c/d") + << QString::fromLatin1("http://a.b.c/de") << false; + QTest::newRow("data3") << QString::fromLatin1("http://a.b.c/d/") + << QString::fromLatin1("http://a.b.c/de") << false; + QTest::newRow("data4") << QString::fromLatin1("http://a.b.c/d/") + << QString::fromLatin1("http://a.b.c/d/e") << true; + + +} + +void tst_QUrl::toString_constructed_data() +{ + QTest::addColumn<QString>("scheme"); + QTest::addColumn<QString>("userName"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("host"); + QTest::addColumn<int>("port"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QByteArray>("query"); + QTest::addColumn<QString>("fragment"); + QTest::addColumn<QString>("asString"); + QTest::addColumn<QByteArray>("asEncoded"); + + QString n(""); + + QTest::newRow("data1") << n << n << n << QString::fromLatin1("qt.nokia.com") << -1 << QString::fromLatin1("index.html") + << QByteArray() << n << QString::fromLatin1("//qt.nokia.com/index.html") + << QByteArray("//qt.nokia.com/index.html"); + QTest::newRow("data2") << QString::fromLatin1("file") << n << n << n << -1 << QString::fromLatin1("/root") << QByteArray() + << n << QString::fromLatin1("file:///root") << QByteArray("file:///root"); + QTest::newRow("userAndPass") << QString::fromLatin1("http") << QString::fromLatin1("dfaure") << QString::fromLatin1("kde") + << "kde.org" << 443 << QString::fromLatin1("/") << QByteArray() << n + << QString::fromLatin1("http://dfaure:kde@kde.org:443/") << QByteArray("http://dfaure:kde@kde.org:443/"); + QTest::newRow("PassWithoutUser") << QString::fromLatin1("http") << n << QString::fromLatin1("kde") + << "kde.org" << 443 << QString::fromLatin1("/") << QByteArray() << n + << QString::fromLatin1("http://:kde@kde.org:443/") << QByteArray("http://:kde@kde.org:443/"); +} + +void tst_QUrl::toString_constructed() +{ + QFETCH(QString, scheme); + QFETCH(QString, userName); + QFETCH(QString, password); + QFETCH(QString, host); + QFETCH(int, port); + QFETCH(QString, path); + QFETCH(QByteArray, query); + QFETCH(QString, fragment); + QFETCH(QString, asString); + QFETCH(QByteArray, asEncoded); + + QUrl url; + if (!scheme.isEmpty()) + url.setScheme(scheme); + if (!userName.isEmpty()) + url.setUserName(userName); + if (!password.isEmpty()) + url.setPassword(password); + if (!host.isEmpty()) + url.setHost(host); + if (port != -1) + url.setPort(port); + if (!path.isEmpty()) + url.setPath(path); + if (!query.isEmpty()) + url.setEncodedQuery(query); + if (!fragment.isEmpty()) + url.setFragment(fragment); + + QVERIFY(url.isValid()); + QCOMPARE(url.toString(), asString); + QCOMPARE(QString::fromLatin1(url.toEncoded()), QString::fromLatin1(asEncoded)); // readable in case of differences + QCOMPARE(url.toEncoded(), asEncoded); +} + + +void tst_QUrl::isParentOf() +{ + QFETCH(QString, parent); + QFETCH(QString, child); + QFETCH(bool, trueFalse); + + QUrl url(parent); + QCOMPARE(url.isParentOf(QUrl(child)), trueFalse); +} + +void tst_QUrl::toLocalFile_data() +{ + QTest::addColumn<QString>("theUrl"); + QTest::addColumn<QString>("theFile"); + + QTest::newRow("data0") << QString::fromLatin1("file:/a.txt") << QString::fromLatin1("/a.txt"); + QTest::newRow("data4") << QString::fromLatin1("file:///a.txt") << QString::fromLatin1("/a.txt"); + QTest::newRow("data5") << QString::fromLatin1("file:///c:/a.txt") << QString::fromLatin1("c:/a.txt"); + QTest::newRow("data6") << QString::fromLatin1("file://somehost/somedir/somefile") << QString::fromLatin1("//somehost/somedir/somefile"); + QTest::newRow("data7") << QString::fromLatin1("file://somehost/") << QString::fromLatin1("//somehost/"); + QTest::newRow("data8") << QString::fromLatin1("file://somehost") << QString::fromLatin1("//somehost"); + QTest::newRow("data9") << QString::fromLatin1("file:////somehost/somedir/somefile") << QString::fromLatin1("//somehost/somedir/somefile"); + QTest::newRow("data10") << QString::fromLatin1("FILE:/a.txt") << QString::fromLatin1("/a.txt"); + + // and some that result in empty (i.e., not local) + QTest::newRow("xdata0") << QString::fromLatin1("/a.txt") << QString(); + QTest::newRow("xdata1") << QString::fromLatin1("//a.txt") << QString(); + QTest::newRow("xdata2") << QString::fromLatin1("///a.txt") << QString(); + QTest::newRow("xdata3") << QString::fromLatin1("foo:/a.txt") << QString(); + QTest::newRow("xdata4") << QString::fromLatin1("foo://a.txt") << QString(); + QTest::newRow("xdata5") << QString::fromLatin1("foo:///a.txt") << QString(); +} + +void tst_QUrl::toLocalFile() +{ + QFETCH(QString, theUrl); + QFETCH(QString, theFile); + + QUrl url(theUrl); + QCOMPARE(url.toLocalFile(), theFile); +} + +void tst_QUrl::fromLocalFile_data() +{ + QTest::addColumn<QString>("theFile"); + QTest::addColumn<QString>("theUrl"); + QTest::addColumn<QString>("thePath"); + + QTest::newRow("data0") << QString::fromLatin1("/a.txt") << QString::fromLatin1("file:///a.txt") << QString::fromLatin1("/a.txt"); + QTest::newRow("data1") << QString::fromLatin1("a.txt") << QString::fromLatin1("file:a.txt") << QString::fromLatin1("a.txt"); + QTest::newRow("data2") << QString::fromLatin1("/a/b.txt") << QString::fromLatin1("file:///a/b.txt") << QString::fromLatin1("/a/b.txt"); + QTest::newRow("data3") << QString::fromLatin1("c:/a.txt") << QString::fromLatin1("file:///c:/a.txt") << QString::fromLatin1("/c:/a.txt"); + QTest::newRow("data4") << QString::fromLatin1("//somehost/somedir/somefile") << QString::fromLatin1("file://somehost/somedir/somefile") + << QString::fromLatin1("/somedir/somefile"); + QTest::newRow("data5") << QString::fromLatin1("//somehost") << QString::fromLatin1("file://somehost") + << QString::fromLatin1(""); + QTest::newRow("data6") << QString::fromLatin1("//somehost/") << QString::fromLatin1("file://somehost/") + << QString::fromLatin1("/"); +} + +void tst_QUrl::fromLocalFile() +{ + QFETCH(QString, theFile); + QFETCH(QString, theUrl); + QFETCH(QString, thePath); + + QUrl url = QUrl::fromLocalFile(theFile); + + QCOMPARE(url.toString(), theUrl); + QCOMPARE(url.path(), thePath); +} + +void tst_QUrl::compat_legacy() +{ + { + QUrl u( "file:bar" ); + QCOMPARE( u.toString(QUrl::RemoveScheme), QString("bar") ); + } + + /* others + */ + { + QUrl u( "http://qt.nokia.com/images/ban/pgs_front.jpg" ); + QCOMPARE( u.path(), QString("/images/ban/pgs_front.jpg") ); + } + { + QUrl tmp( "http://qt.nokia.com/images/ban/" ); + QUrl u = tmp.resolved(QString("pgs_front.jpg")); + QCOMPARE( u.path(), QString("/images/ban/pgs_front.jpg") ); + } + { + QUrl tmp; + QUrl u = tmp.resolved(QString("http://qt.nokia.com/images/ban/pgs_front.jpg")); + QCOMPARE( u.path(), QString("/images/ban/pgs_front.jpg") ); + } + { + QUrl tmp; + QUrl u = tmp.resolved(QString("http://qt.nokia.com/images/ban/pgs_front.jpg")); + QFileInfo fi(u.path()); + u.setPath(fi.path()); + QCOMPARE( u.path(), QString("/images/ban") ); + } +} + +void tst_QUrl::compat_constructor_01_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<QString>("res"); + + //next we fill it with data + QTest::newRow( "data0" ) << QString("Makefile") << QString("Makefile"); // nolonger add file by default + QTest::newRow( "data1" ) << QString("Makefile") << QString("Makefile"); + QTest::newRow( "data2" ) << QString("ftp://ftp.qt.nokia.com/qt/INSTALL") << QString("ftp://ftp.qt.nokia.com/qt/INSTALL"); + QTest::newRow( "data3" ) << QString("ftp://ftp.qt.nokia.com/qt/INSTALL") << QString("ftp://ftp.qt.nokia.com/qt/INSTALL"); +} + +void tst_QUrl::compat_constructor_01() +{ + /* The following should work as expected: + * + * QUrlOperator op; + * op.copy( QString( "Makefile" ), + * QString("ftp://rms:grmpf12@nibbler/home/rms/tmp"), + * false ); + * + * as well as the following: + * + * QUrlOperator op; + * op.copy(QString("ftp://ftp.qt.nokia.com/qt/INSTALL"), "."); + */ + QFETCH( QString, urlStr ); + + { + QUrl empty; + QUrl u = empty.resolved(urlStr); + + QTEST( u.toString(), "res" ); + } + { + QUrl empty; + QUrl u = empty.resolved(urlStr); + + QTEST( u.toString(), "res" ); + } +} + +void tst_QUrl::compat_constructor_02_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("res"); + + //next we fill it with data + QTest::newRow( "data0" ) << QString("ftp://ftp.qt.nokia.com/qt") << QString("INSTALL") << QString("ftp://ftp.qt.nokia.com/INSTALL"); + QTest::newRow( "data1" ) << QString("ftp://ftp.qt.nokia.com/qt/") << QString("INSTALL") << QString("ftp://ftp.qt.nokia.com/qt/INSTALL"); +} + +void tst_QUrl::compat_constructor_02() +{ + /* The following should work as expected: + * + * QUrlOperator op( "ftp://ftp.qt.nokia.com/qt" ); + * op.copy(QString("INSTALL"), "."); + */ + QFETCH( QString, urlStr ); + QFETCH( QString, fileName ); + + QUrl tmp( urlStr ); + QUrl u = tmp.resolved(fileName); + + QTEST( u.toString(), "res" ); +} + +void tst_QUrl::compat_constructor_03_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<QString>("res"); + + //next we fill it with data + QTest::newRow( "protocol00" ) << QString( "http://qt.nokia.com/index.html" ) << QString( "http://qt.nokia.com/index.html" ); + QTest::newRow( "protocol01" ) << QString( "http://qt.nokia.com" ) << QString( "http://qt.nokia.com" ); + QTest::newRow( "protocol02" ) << QString( "http://qt.nokia.com/" ) << QString( "http://qt.nokia.com/" ); + QTest::newRow( "protocol03" ) << QString( "http://qt.nokia.com/foo" ) << QString( "http://qt.nokia.com/foo" ); + QTest::newRow( "protocol04" ) << QString( "http://qt.nokia.com/foo/" ) << QString( "http://qt.nokia.com/foo/" ); + QTest::newRow( "protocol05" ) << QString( "ftp://ftp.qt.nokia.com/foo/index.txt" ) << QString( "ftp://ftp.qt.nokia.com/foo/index.txt" ); + + QTest::newRow( "local00" ) << QString( "/foo" ) << QString( "/foo" ); + QTest::newRow( "local01" ) << QString( "/foo/" ) << QString( "/foo/" ); + QTest::newRow( "local02" ) << QString( "/foo/bar" ) << QString( "/foo/bar" ); + QTest::newRow( "local03" ) << QString( "/foo/bar/" ) << QString( "/foo/bar/" ); + QTest::newRow( "local04" ) << QString( "foo" ) << QString( "foo" ); + QTest::newRow( "local05" ) << QString( "foo/" ) << QString( "foo/" ); + QTest::newRow( "local06" ) << QString( "foo/bar" ) << QString( "foo/bar" ); + QTest::newRow( "local07" ) << QString( "foo/bar/" ) << QString( "foo/bar/" ); + QTest::newRow( "local09" ) << QString( "" ) << QString( "" ); + + QTest::newRow( "file00" ) << QString( "file:/foo" ) << QString( "file:///foo" ); + QTest::newRow( "file01" ) << QString( "file:/foo/" ) << QString( "file:///foo/" ); + QTest::newRow( "file02" ) << QString( "file:/foo/bar" ) << QString( "file:///foo/bar" ); + QTest::newRow( "file03" ) << QString( "file:/foo/bar/" ) << QString( "file:///foo/bar/" ); + QTest::newRow( "relProtocol00" ) << QString( "foo:bar" ) << QString( "foo:bar" ); + QTest::newRow( "relProtocol01" ) << QString( "foo:/bar" ) << QString( "foo:/bar" ); + + QTest::newRow( "windowsDrive00" ) << QString( "c:/" ) << QString( "c:/" ); + QTest::newRow( "windowsDrive01" ) << QString( "c:" ) << QString( "c:" ); + QTest::newRow( "windowsDrive02" ) << QString( "c:/WinNT/" ) << QString( "c:/WinNT/" ); + QTest::newRow( "windowsDrive03" ) << QString( "c:/autoexec.bat" ) << QString( "c:/autoexec.bat" ); + QTest::newRow( "windowsDrive04" ) << QString( "c:WinNT/" ) << QString( "c:WinNT/" ); + QTest::newRow( "windowsDrive05" ) << QString( "c:autoexec.bat" ) << QString( "c:autoexec.bat" ); + + QTest::newRow("task31280") << QString("protocol://host") << QString("protocol://host"); +} + +void tst_QUrl::compat_constructor_03() +{ + QFETCH( QString, urlStr ); + + QUrl u( urlStr ); + QTEST( u.toString(), "res" ); +} + +void tst_QUrl::compat_isValid_01_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<bool>("res"); + + QTest::newRow( "ok_01" ) << QString("ftp://ftp.qt.nokia.com/qt/INSTALL") << (bool)true; + QTest::newRow( "ok_02" ) << QString( "file:/foo") << (bool)true; + QTest::newRow( "ok_03" ) << QString( "file:foo") << (bool)true; + + QTest::newRow( "err_01" ) << QString("#ftp://ftp.qt.nokia.com/qt/INSTALL") << (bool)true; + QTest::newRow( "err_02" ) << QString( "file:/::foo") << (bool)true; +} + +void tst_QUrl::compat_isValid_01() +{ + QFETCH( QString, urlStr ); + QFETCH( bool, res ); + + QUrl url( urlStr ); + QVERIFY( url.isValid() == res ); +} + +void tst_QUrl::compat_isValid_02_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("host"); + QTest::addColumn<int>("port"); + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("res"); + + QString n = ""; + + QTest::newRow( "ok_01" ) << n << n << n << n << -1 << QString("path") << (bool)true; + QTest::newRow( "ok_02" ) << QString("ftp") << n << n << QString("ftp.qt.nokia.com") << -1 << n << (bool)true; + QTest::newRow( "ok_03" ) << QString("ftp") << QString("foo") << n << QString("ftp.qt.nokia.com") << -1 << n << (bool)true; + QTest::newRow( "ok_04" ) << QString("ftp") << QString("foo") << QString("bar") << QString("ftp.qt.nokia.com") << -1 << n << (bool)true; + QTest::newRow( "ok_05" ) << QString("ftp") << n << n << QString("ftp.qt.nokia.com") << -1 << QString("path")<< (bool)true; + QTest::newRow( "ok_06" ) << QString("ftp") << QString("foo") << n << QString("ftp.qt.nokia.com") << -1 << QString("path") << (bool)true; + QTest::newRow( "ok_07" ) << QString("ftp") << QString("foo") << QString("bar") << QString("ftp.qt.nokia.com") << -1 << QString("path")<< (bool)true; + + QTest::newRow( "err_01" ) << n << n << n << n << -1 << n << (bool)false; + QTest::newRow( "err_02" ) << QString("ftp") << n << n << n << -1 << n << (bool)true; + QTest::newRow( "err_03" ) << n << QString("foo") << n << n << -1 << n << (bool)true; + QTest::newRow( "err_04" ) << n << n << QString("bar") << n << -1 << n << (bool)true; + QTest::newRow( "err_05" ) << n << n << n << QString("ftp.qt.nokia.com") << -1 << n << (bool)true; + QTest::newRow( "err_06" ) << n << n << n << n << 80 << n << (bool)true; + QTest::newRow( "err_07" ) << QString("ftp") << QString("foo") << n << n << -1 << n << (bool)true; + QTest::newRow( "err_08" ) << QString("ftp") << n << QString("bar") << n << -1 << n << (bool)true; + QTest::newRow( "err_09" ) << QString("ftp") << QString("foo") << QString("bar") << n << -1 << n << (bool)true; +} + +void tst_QUrl::compat_isValid_02() +{ + QFETCH( QString, protocol ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, host ); + QFETCH( int, port ); + QFETCH( QString, path ); + QFETCH( bool, res ); + + QUrl url; + if ( !protocol.isEmpty() ) + url.setScheme( protocol ); + if ( !user.isEmpty() ) + url.setUserName( user ); + if ( !password.isEmpty() ) + url.setPassword( password ); + if ( !host.isEmpty() ) + url.setHost( host ); + if ( port != -1 ) + url.setPort( port ); + if ( !path.isEmpty() ) + url.setPath( path ); + + QVERIFY( url.isValid() == res ); +} + +void tst_QUrl::compat_path_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<QString>("res"); + + QTest::newRow( "protocol00" ) << "http://qt.nokia.com/images/ban/pgs_front.jpg" << "/images/ban/pgs_front.jpg"; + +#if defined( Q_OS_WIN32 ) + QTest::newRow( "winShare00" ) << "//Anarki/homes" << "/homes"; +#endif +} + +void tst_QUrl::compat_path() +{ + QFETCH( QString, url ); + + QUrl u( url ); + QTEST( u.path(), "res" ); +} + +void tst_QUrl::compat_fileName_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<QString>("fileName"); + +#ifdef Q_OS_WIN32 + QTest::newRow( "Windows - DrivePathFileName - \\" ) << QString("c:\\windows\\tmp\\filename.txt")<< QString("filename.txt"); + QTest::newRow( "Windows - DrivePathFileName - /" ) << QString("c:/windows/tmp/filename.txt") << QString("filename.txt"); + QTest::newRow( "Windows - DrivePathWithSlash - \\" ) << QString("c:\\windows\\tmp\\") << QString(); + QTest::newRow( "Windows - DrivePathWithSlash - /" ) << QString("c:/windows/tmp/") << QString(); + QTest::newRow( "Windows - DrivePathWithoutSlash - \\" ) << QString("c:/windows/tmp") << QString("tmp"); + QTest::newRow( "Windows - DrivePathWithoutSlash - /" ) << QString("c:/windows/tmp") << QString("tmp"); +#endif + QTest::newRow( "Path00" ) << QString("/") << QString(); + QTest::newRow( "Path01" ) << QString("/home/dev/test/") << QString(); + QTest::newRow( "PathFileName00" ) << QString("/home/dev/test") << QString("test"); +} + +void tst_QUrl::compat_fileName() +{ + QFETCH( QString, url ); + QFETCH( QString, fileName ); + QUrl fileUrl = QUrl::fromLocalFile(url); + QFileInfo fi(fileUrl.toLocalFile()); + QCOMPARE( fi.fileName(), fileName ); +} + +void tst_QUrl::compat_decode_data() +{ + QTest::addColumn<QByteArray>("encodedString"); + QTest::addColumn<QString>("decodedString"); + + QTest::newRow("NormalString") << QByteArray("filename") << QString("filename"); + QTest::newRow("NormalStringEncoded") << QByteArray("file%20name") << QString("file name"); + QTest::newRow("JustEncoded") << QByteArray("%20") << QString(" "); + QTest::newRow("HTTPUrl") << QByteArray("http://qt.nokia.com") << QString("http://qt.nokia.com"); + QTest::newRow("HTTPUrlEncoded") << QByteArray("http://qt%20nokia%20com") << QString("http://qt nokia com"); + QTest::newRow("EmptyString") << QByteArray("") << QString(""); + QTest::newRow("Task27166") << QByteArray("Fran%C3%A7aise") << QString("Française"); +} + +void tst_QUrl::compat_decode() +{ + QFETCH(QByteArray, encodedString); + QFETCH(QString, decodedString); + + QCOMPARE(QUrl::fromPercentEncoding(encodedString), decodedString); +} + +void tst_QUrl::compat_encode_data() +{ + QTest::addColumn<QString>("decodedString"); + QTest::addColumn<QByteArray>("encodedString"); + + QTest::newRow("NormalString") << QString("filename") << QByteArray("filename"); + QTest::newRow("NormalStringEncoded") << QString("file name") << QByteArray("file%20name"); + QTest::newRow("JustEncoded") << QString(" ") << QByteArray("%20"); + QTest::newRow("HTTPUrl") << QString("http://qt.nokia.com") << QByteArray("http%3A//qt.nokia.com"); + QTest::newRow("HTTPUrlEncoded") << QString("http://qt nokia com") << QByteArray("http%3A//qt%20nokia%20com"); + QTest::newRow("EmptyString") << QString("") << QByteArray(""); + QTest::newRow("Task27166") << QString::fromLatin1("Française") << QByteArray("Fran%C3%A7aise"); +} + +void tst_QUrl::compat_encode() +{ + QFETCH(QString, decodedString); + QFETCH(QByteArray, encodedString); + + QCOMPARE(QUrl::toPercentEncoding(decodedString, "/.").constData(), encodedString.constData()); +} + + +void tst_QUrl::relative() +{ + QUrl url("../ole"); + QCOMPARE(url.path(), QString::fromLatin1("../ole")); + + QUrl url2("./"); + QCOMPARE(url2.path(), QString::fromLatin1("./")); + + QUrl url3(".."); + QCOMPARE(url3.path(), QString::fromLatin1("..")); + + QUrl url4("../.."); + QCOMPARE(url4.path(), QString::fromLatin1("../..")); +} + +void tst_QUrl::percentEncoding_data() +{ + QTest::addColumn<QString>("original"); + QTest::addColumn<QByteArray>("encoded"); + + QTest::newRow("test_01") << QString::fromLatin1("sdfsdf") << QByteArray("sdfsdf"); + QTest::newRow("test_02") << QString::fromLatin1("æss") << QByteArray("%C3%A6ss"); + // not unreserved or reserved + QTest::newRow("test_03") << QString::fromLatin1("{}") << QByteArray("%7B%7D"); +} + +void tst_QUrl::percentEncoding() +{ + QFETCH(QString, original); + QFETCH(QByteArray, encoded); + + QCOMPARE(QUrl(original).toEncoded().constData(), encoded.constData()); + QVERIFY(QUrl::fromEncoded(QUrl(original).toEncoded()) == QUrl(original)); + QCOMPARE(QUrl::fromEncoded(QUrl(original).toEncoded()).toString(), original); + QVERIFY(QUrl::fromEncoded(encoded) == QUrl(original)); +} + +void tst_QUrl::toPercentEncoding_data() +{ + QTest::addColumn<QString>("original"); + QTest::addColumn<QByteArray>("encoded"); + QTest::addColumn<QByteArray>("excludeInEncoding"); + QTest::addColumn<QByteArray>("includeInEncoding"); + + QTest::newRow("test_01") << QString::fromLatin1("abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~") + << QByteArray("abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_02") << QString::fromLatin1("{\t\n\r^\"abc}") + << QByteArray("%7B%09%0A%0D%5E%22abc%7D") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_03") << QString::fromLatin1("://?#[]@!$&'()*+,;=") + << QByteArray("%3A%2F%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_04") << QString::fromLatin1("://?#[]@!$&'()*+,;=") + << QByteArray("%3A%2F%2F%3F%23%5B%5D%40!$&'()*+,;=") + << QByteArray("!$&'()*+,;=") + << QByteArray(""); + QTest::newRow("test_05") << QString::fromLatin1("abcd") + << QByteArray("a%62%63d") + << QByteArray("") + << QByteArray("bc"); +} + +void tst_QUrl::toPercentEncoding() +{ + QFETCH(QString, original); + QFETCH(QByteArray, encoded); + QFETCH(QByteArray, excludeInEncoding); + QFETCH(QByteArray, includeInEncoding); + + QByteArray encodedUrl = QUrl::toPercentEncoding(original, excludeInEncoding, includeInEncoding); + QCOMPARE(encodedUrl.constData(), encoded.constData()); + QCOMPARE(original, QUrl::fromPercentEncoding(encodedUrl)); +} + +void tst_QUrl::swap() +{ + QUrl u1(QLatin1String("http://qt.nokia.com")), u2(QLatin1String("http://www.kdab.com")); + u1.swap(u2); + QCOMPARE(u2.host(),QLatin1String("qt.nokia.com")); + QCOMPARE(u1.host(),QLatin1String("www.kdab.com")); +} + +void tst_QUrl::symmetry() +{ + QUrl url(QString::fromLatin1("http://www.räksmörgås.se/pub?a=b&a=dø&a=f#vræl")); + QCOMPARE(url.scheme(), QString::fromLatin1("http")); + QCOMPARE(url.host(), QString::fromLatin1("www.räksmörgås.se")); + QCOMPARE(url.path(), QString::fromLatin1("/pub")); + // this will be encoded ... + QCOMPARE(url.encodedQuery().constData(), QString::fromLatin1("a=b&a=d%C3%B8&a=f").toLatin1().constData()); + // unencoded + QCOMPARE(url.allQueryItemValues("a").join("").toLatin1().constData(), "bdøf"); + QCOMPARE(url.fragment(), QString::fromLatin1("vræl")); + + QUrl onlyHost("//qt.nokia.com"); + QCOMPARE(onlyHost.toString(), QString::fromLatin1("//qt.nokia.com")); + + { + QString urlString = QString::fromLatin1("http://desktop:33326/upnp/{32f525a6-6f31-426e-91ca-01c2e6c2c57e}"); + QUrl urlPreviewList(urlString); + QCOMPARE(urlPreviewList.toString(), urlString); + QByteArray b = urlPreviewList.toEncoded(); + QCOMPARE(b.constData(), "http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D"); + QCOMPARE(QUrl::fromEncoded(b).toString(), urlString); + + }{ + QString urlString = QString::fromLatin1("http://desktop:53423/deviceDescription?uuid={7977c17b-00bf-4af9-894e-fed28573c3a9}"); + QUrl urlPreviewList(urlString); + QCOMPARE(urlPreviewList.toString(), urlString); + QByteArray b = urlPreviewList.toEncoded(); + QCOMPARE(b.constData(), "http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D"); + QCOMPARE(QUrl::fromEncoded(b).toString(), urlString); + } +} + + +void tst_QUrl::ipv6_data() +{ + QTest::addColumn<QString>("ipv6Auth"); + QTest::addColumn<bool>("isValid"); + + QTest::newRow("case 1") << QString::fromLatin1("//[56:56:56:56:56:56:56:56]") << true; + QTest::newRow("case 2") << QString::fromLatin1("//[::56:56:56:56:56:56:56]") << true; + QTest::newRow("case 3") << QString::fromLatin1("//[56::56:56:56:56:56:56]") << true; + QTest::newRow("case 4") << QString::fromLatin1("//[56:56::56:56:56:56:56]") << true; + QTest::newRow("case 5") << QString::fromLatin1("//[56:56:56::56:56:56:56]") << true; + QTest::newRow("case 6") << QString::fromLatin1("//[56:56:56:56::56:56:56]") << true; + QTest::newRow("case 7") << QString::fromLatin1("//[56:56:56:56:56::56:56]") << true; + QTest::newRow("case 8") << QString::fromLatin1("//[56:56:56:56:56:56::56]") << true; + QTest::newRow("case 9") << QString::fromLatin1("//[56:56:56:56:56:56:56::]") << true; + QTest::newRow("case 4 with one less") << QString::fromLatin1("//[56::56:56:56:56:56]") << true; + QTest::newRow("case 4 with less and ip4") << QString::fromLatin1("//[56::56:56:56:127.0.0.1]") << true; + QTest::newRow("case 7 with one and ip4") << QString::fromLatin1("//[56::255.0.0.0]") << true; + QTest::newRow("case 2 with ip4") << QString::fromLatin1("//[::56:56:56:56:56:0.0.0.255]") << true; + QTest::newRow("case 2 with half ip4") << QString::fromLatin1("//[::56:56:56:56:56:56:0.255]") << false; + QTest::newRow("case 4 with less and ip4 and port and useinfo") << QString::fromLatin1("//user:pass@[56::56:56:56:127.0.0.1]:99") << true; + QTest::newRow("case :,") << QString::fromLatin1("//[:,]") << false; + QTest::newRow("case ::bla") << QString::fromLatin1("//[::bla]") << false; +} + +void tst_QUrl::ipv6() +{ + QFETCH(QString, ipv6Auth); + QFETCH(bool, isValid); + + QUrl url(ipv6Auth); + + QCOMPARE(url.isValid(), isValid); + if (url.isValid()) { + QCOMPARE(url.toString(), ipv6Auth); + url.setHost(url.host()); + QCOMPARE(url.toString(), ipv6Auth); + } +}; + +void tst_QUrl::ipv6_2_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("output"); + + QTest::newRow("[::ffff:129.144.52.38]") + << QString("http://[::ffff:129.144.52.38]/cgi/test.cgi") + << QString("http://[::ffff:129.144.52.38]/cgi/test.cgi"); + QTest::newRow("[::FFFF:129.144.52.38]") + << QString("http://[::FFFF:129.144.52.38]/cgi/test.cgi") + << QString("http://[::ffff:129.144.52.38]/cgi/test.cgi"); +} + +void tst_QUrl::ipv6_2() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + QUrl url(input); + QCOMPARE(url.toString(), output); + url.setHost(url.host()); + QCOMPARE(url.toString(), output); +} + +void tst_QUrl::moreIpv6() +{ + QUrl waba1("http://www.kde.org/cgi/test.cgi"); + waba1.setHost("::ffff:129.144.52.38"); + QCOMPARE(QString::fromLatin1(waba1.toEncoded()), QString::fromLatin1("http://[::ffff:129.144.52.38]/cgi/test.cgi")); +} + +void tst_QUrl::punycode_data() +{ + QTest::addColumn<QString>("original"); + QTest::addColumn<QByteArray>("encoded"); + + QTest::newRow("øl") << QString::fromLatin1("øl") << QByteArray("xn--l-4ga"); + QTest::newRow("Bühler") << QString::fromLatin1("Bühler") << QByteArray("xn--Bhler-kva"); + QTest::newRow("räksmörgås") << QString::fromLatin1("räksmörgås") << QByteArray("xn--rksmrgs-5wao1o"); +} + +void tst_QUrl::punycode() +{ + QFETCH(QString, original); + QFETCH(QByteArray, encoded); + + QCOMPARE(QUrl::fromPunycode(encoded), original); + QCOMPARE(QUrl::fromPunycode(QUrl::toPunycode(original)), original); + QCOMPARE(QUrl::toPunycode(original).constData(), encoded.constData()); +} + +void tst_QUrl::isRelative_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<bool>("trueFalse"); + + QTest::newRow("not") << QString::fromLatin1("http://qt.nokia.com") << false; + QTest::newRow("55288") << QString::fromLatin1("node64.html#fig:form:ana") << true; + + // kde + QTest::newRow("mailto: URL, is relative") << "mailto:faure@kde.org" << false; + QTest::newRow("man: URL, is relative") << "man:mmap" << false; + QTest::newRow("javascript: URL, is relative") << "javascript:doSomething()" << false; + QTest::newRow("file: URL, is relative") << "file:/blah" << false; + QTest::newRow("/path, is relative") << "/path" << true; + QTest::newRow("something, is relative") << "something" << true; + // end kde +} + +void tst_QUrl::isRelative() +{ + QFETCH(QString, url); + QFETCH(bool, trueFalse); + + QCOMPARE(QUrl(url).isRelative(), trueFalse); +} + +void tst_QUrl::queryItems() +{ + QUrl url; + QVERIFY(!url.hasQuery()); + + QList<QPair<QString, QString> > newItems; + newItems += qMakePair(QString("2"), QString("b")); + newItems += qMakePair(QString("1"), QString("a")); + newItems += qMakePair(QString("3"), QString("c")); + newItems += qMakePair(QString("4"), QString("a b")); + newItems += qMakePair(QString("5"), QString("&")); + newItems += qMakePair(QString("foo bar"), QString("hello world")); + newItems += qMakePair(QString("foo+bar"), QString("hello+world")); + newItems += qMakePair(QString("tex"), QString("a + b = c")); + url.setQueryItems(newItems); + QVERIFY(url.hasQuery()); + + QList<QPair<QString, QString> > setItems = url.queryItems(); + QVERIFY(newItems == setItems); + + url.addQueryItem("1", "z"); + + QVERIFY(url.hasQueryItem("1")); + QCOMPARE(url.queryItemValue("1").toLatin1().constData(), "a"); + + url.addQueryItem("1", "zz"); + + QStringList expected; + expected += "a"; + expected += "z"; + expected += "zz"; + QCOMPARE(expected, url.allQueryItemValues("1")); + + url.removeQueryItem("1"); + QCOMPARE(url.allQueryItemValues("1").size(), 2); + QCOMPARE(url.queryItemValue("1").toLatin1().constData(), "z"); + + url.removeAllQueryItems("1"); + QVERIFY(!url.hasQueryItem("1")); + + QCOMPARE(url.queryItemValue("4").toLatin1().constData(), "a b"); + QCOMPARE(url.queryItemValue("5").toLatin1().constData(), "&"); + QCOMPARE(url.queryItemValue("tex").toLatin1().constData(), "a + b = c"); + QCOMPARE(url.queryItemValue("foo bar").toLatin1().constData(), "hello world"); + url.setUrl("http://www.google.com/search?q=a+b"); + QCOMPARE(url.queryItemValue("q"), QString("a+b")); + url.setUrl("http://www.google.com/search?q=a=b"); // invalid, but should be tolerated + QCOMPARE(url.queryItemValue("q"), QString("a=b")); +} + +void tst_QUrl::hasQuery_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<bool>("trueFalse"); + + QTest::newRow("no query items") << "http://www.foo.bar" << false; + + QTest::newRow("empty query") << "http://www.foo.bar?" << true; + QTest::newRow("empty query 2") << "http://www.foo.bar/?" << true; + + QTest::newRow("query") << "http://www.foo.bar?query" << true; + QTest::newRow("query=") << "http://www.foo.bar?query=" << true; + QTest::newRow("query=value") << "http://www.foo.bar?query=value" << true; + + QTest::newRow("%3f") << "http://www.foo.bar/file%3f" << false; + QTest::newRow("%3f-query") << "http://www.foo.bar/file%3fquery" << false; + QTest::newRow("%3f-query=value") << "http://www.foo.bar/file%3fquery=value" << false; +} + +void tst_QUrl::hasQuery() +{ + QFETCH(QString, url); + QFETCH(bool, trueFalse); + + QUrl qurl(url); + QCOMPARE(qurl.hasQuery(), trueFalse); + QCOMPARE(qurl.encodedQuery().isNull(), !trueFalse); +} + +void tst_QUrl::hasQueryItem_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<QString>("item"); + QTest::addColumn<bool>("trueFalse"); + + QTest::newRow("no query items") << "http://www.foo.bar" << "baz" << false; + QTest::newRow("query item: hello") << "http://www.foo.bar?hello=world" << "hello" << true; + QTest::newRow("no query item: world") << "http://www.foo.bar?hello=world" << "world" << false; + QTest::newRow("query item: qt") << "http://www.foo.bar?hello=world&qt=rocks" << "qt" << true; +} + +void tst_QUrl::hasQueryItem() +{ + QFETCH(QString, url); + QFETCH(QString, item); + QFETCH(bool, trueFalse); + + QCOMPARE(QUrl(url).hasQueryItem(item), trueFalse); +} + +void tst_QUrl::nameprep() +{ + QUrl url(QString::fromUtf8("http://www.fu""\xc3""\x9f""ball.de/")); + QCOMPARE(url.toString(), QString::fromLatin1("http://www.fussball.de/")); +} + +void tst_QUrl::isValid() +{ + { + QUrl url(QString("A=B")); + QVERIFY(url.isValid()); + QCOMPARE(url.path(), QString("A=B")); + } + { + QUrl url = QUrl::fromEncoded("http://strange<username>@ok-hostname/", QUrl::StrictMode); + QVERIFY(!url.isValid()); + // < and > are not allowed in userinfo in strict mode + url.setUserName("normal_username"); + QVERIFY(url.isValid()); + } + { + QUrl url = QUrl::fromEncoded("http://strange<username>@ok-hostname/"); + QVERIFY(url.isValid()); + // < and > are allowed in tolerant mode + } + { + QUrl url = QUrl::fromEncoded("http://strange;hostname/here"); + QVERIFY(!url.isValid()); + QCOMPARE(url.path(), QString("/here")); + url.setAuthority("strange;hostname"); + QVERIFY(!url.isValid()); + url.setAuthority("foobar@bar"); + QVERIFY(url.isValid()); + url.setAuthority("strange;hostname"); + QVERIFY(!url.isValid()); + QVERIFY(url.errorString().contains("invalid hostname")); + } + + { + QUrl url = QUrl::fromEncoded("foo://stuff;1/g"); + QVERIFY(!url.isValid()); + QCOMPARE(url.path(), QString("/g")); + url.setHost("stuff;1"); + QVERIFY(!url.isValid()); + url.setHost("stuff-1"); + QVERIFY(url.isValid()); + url.setHost("stuff;1"); + QVERIFY(!url.isValid()); + QVERIFY(url.errorString().contains("invalid hostname")); + } + +} + +void tst_QUrl::schemeValidator_data() +{ + QTest::addColumn<QByteArray>("encodedUrl"); + QTest::addColumn<bool>("result"); + QTest::addColumn<QString>("toString"); + + QTest::newRow("empty") << QByteArray() << false << QString(); + + // ftp + QTest::newRow("ftp:") << QByteArray("ftp:") << true << QString("ftp:"); + QTest::newRow("ftp://ftp.qt.nokia.com") + << QByteArray("ftp://ftp.qt.nokia.com") + << true << QString("ftp://ftp.qt.nokia.com"); + QTest::newRow("ftp://ftp.qt.nokia.com/") + << QByteArray("ftp://ftp.qt.nokia.com/") + << true << QString("ftp://ftp.qt.nokia.com/"); + QTest::newRow("ftp:/index.html") + << QByteArray("ftp:/index.html") + << false << QString(); + + // mailto + QTest::newRow("mailto:") << QByteArray("mailto:") << true << QString("mailto:"); + QTest::newRow("mailto://smtp.trolltech.com/ole@bull.name") + << QByteArray("mailto://smtp.trolltech.com/ole@bull.name") << false << QString(); + QTest::newRow("mailto:") << QByteArray("mailto:") << true << QString("mailto:"); + QTest::newRow("mailto:ole@bull.name") + << QByteArray("mailto:ole@bull.name") << true << QString("mailto:ole@bull.name"); + + // file + QTest::newRow("file:") << QByteArray("file:/etc/passwd") << true << QString("file:///etc/passwd"); +} + +void tst_QUrl::schemeValidator() +{ + QFETCH(QByteArray, encodedUrl); + QFETCH(bool, result); + QFETCH(QString, toString); + + QUrl url = QUrl::fromEncoded(encodedUrl); + QCOMPARE(url.isValid(), result); +} + +void tst_QUrl::invalidSchemeValidator() +{ + // test that if scheme does not start with an ALPHA, QUrl::isValid() returns false + { + QUrl url("1http://qt.nokia.com", QUrl::StrictMode); + QCOMPARE(url.isValid(), false); + } + { + QUrl url("http://qt.nokia.com"); + url.setScheme("111http://qt.nokia.com"); + QCOMPARE(url.isValid(), false); + } + { + QUrl url = QUrl::fromEncoded("1http://qt.nokia.com", QUrl::StrictMode); + QCOMPARE(url.isValid(), false); + } + + // non-ALPHA character at other positions in the scheme are ok + { + QUrl url("ht111tp://qt.nokia.com", QUrl::StrictMode); + QVERIFY(url.isValid()); + } + { + QUrl url("http://qt.nokia.com"); + url.setScheme("ht123tp://qt.nokia.com"); + QVERIFY(url.isValid()); + } + { + QUrl url = QUrl::fromEncoded("ht321tp://qt.nokia.com", QUrl::StrictMode); + QVERIFY(url.isValid()); + } +} + +void tst_QUrl::tolerantParser() +{ + { + QUrl url("http://www.example.com/path%20with spaces.html"); + QVERIFY(url.isValid()); + QCOMPARE(url.path(), QString("/path with spaces.html")); + QCOMPARE(url.toEncoded(), QByteArray("http://www.example.com/path%20with%20spaces.html")); + url.setUrl("http://www.example.com/path%20with spaces.html", QUrl::StrictMode); + QVERIFY(url.isValid()); + QCOMPARE(url.toEncoded(), QByteArray("http://www.example.com/path%2520with%20spaces.html")); + } + { + QUrl url = QUrl::fromEncoded("http://www.example.com/path%20with spaces.html"); + QVERIFY(url.isValid()); + QCOMPARE(url.path(), QString("/path with spaces.html")); + url.setEncodedUrl("http://www.example.com/path%20with spaces.html", QUrl::StrictMode); + QVERIFY(!url.isValid()); + } + + { + QUrl url15581("http://alain.knaff.linux.lu/bug-reports/kde/percentage%in%url.htm>"); + QVERIFY(url15581.isValid()); + QCOMPARE(url15581.toEncoded().constData(), "http://alain.knaff.linux.lu/bug-reports/kde/percentage%25in%25url.htm%3E"); + } + + { + QUrl webkit22616 = + QUrl::fromEncoded("http://example.com/testya.php?browser-info=s:1400x1050x24:f:9.0%20r152:t:%u0442%u0435%u0441%u0442"); + QVERIFY(webkit22616.isValid()); + QCOMPARE(webkit22616.toEncoded().constData(), + "http://example.com/testya.php?browser-info=s:1400x1050x24:f:9.0%20r152:t:%25u0442%25u0435%25u0441%25u0442"); + } + + { + QUrl url; + url.setUrl("http://foo.bar/[image][1].jpg"); + QVERIFY(url.isValid()); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + + url.setUrl("[].jpg"); + QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg")); + + url.setUrl("/some/[path]/[]"); + QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D")); + + url.setUrl("//[::56:56:56:56:56:56:56]"); + QCOMPARE(url.toEncoded(), QByteArray("//[::56:56:56:56:56:56:56]")); + + url.setUrl("//[::56:56:56:56:56:56:56]#[]"); + QCOMPARE(url.toEncoded(), QByteArray("//[::56:56:56:56:56:56:56]#%5B%5D")); + + url.setUrl("//[::56:56:56:56:56:56:56]?[]"); + QCOMPARE(url.toEncoded(), QByteArray("//[::56:56:56:56:56:56:56]?%5B%5D")); + + url.setUrl("%hello.com/f%"); + QCOMPARE(url.toEncoded(), QByteArray("%25hello.com/f%25")); + + url.setEncodedUrl("http://www.host.com/foo.php?P0=[2006-3-8]"); + QVERIFY(url.isValid()); + + url.setEncodedUrl("http://foo.bar/[image][1].jpg"); + QVERIFY(url.isValid()); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + + url.setEncodedUrl("[].jpg"); + QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg")); + + url.setEncodedUrl("/some/[path]/[]"); + QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D")); + + url.setEncodedUrl("//[::56:56:56:56:56:56:56]"); + QCOMPARE(url.toEncoded(), QByteArray("//[::56:56:56:56:56:56:56]")); + + url.setEncodedUrl("//[::56:56:56:56:56:56:56]#[]"); + QCOMPARE(url.toEncoded(), QByteArray("//[::56:56:56:56:56:56:56]#%5B%5D")); + + url.setEncodedUrl("//[::56:56:56:56:56:56:56]?[]"); + QCOMPARE(url.toEncoded(), QByteArray("//[::56:56:56:56:56:56:56]?%5B%5D")); + + url.setEncodedUrl("data:text/css,div%20{%20border-right:%20solid;%20}"); + QCOMPARE(url.toEncoded(), QByteArray("data:text/css,div%20%7B%20border-right:%20solid;%20%7D")); + } + + { + // task 243557 + QByteArray tsdgeos("http://google.com/c?c=Translation+%C2%BB+trunk|"); + QUrl tsdgeosQUrl; + tsdgeosQUrl.setEncodedUrl(tsdgeos, QUrl::TolerantMode); + QVERIFY(tsdgeosQUrl.isValid()); // failed in Qt-4.4, works in Qt-4.5 + QByteArray tsdgeosExpected("http://google.com/c?c=Translation+%C2%BB+trunk%7C"); + //QCOMPARE(tsdgeosQUrl.toEncoded(), tsdgeosExpected); // unusable output from qtestlib... + QCOMPARE(QString(tsdgeosQUrl.toEncoded()), QString(tsdgeosExpected)); + } + + { + QUrl url; + url.setUrl("http://strange<username>@hostname/", QUrl::TolerantMode); + QVERIFY(url.isValid()); + QCOMPARE(QString(url.toEncoded()), QString("http://strange%3Cusername%3E@hostname/")); + } +} + +void tst_QUrl::correctEncodedMistakes_data() +{ + QTest::addColumn<QByteArray>("encodedUrl"); + QTest::addColumn<bool>("result"); + QTest::addColumn<QString>("toString"); + QTest::addColumn<QByteArray>("toEncoded"); + + QTest::newRow("%") << QByteArray("%") << true << QString("%") << QByteArray("%25"); + QTest::newRow("3%") << QByteArray("3%") << true << QString("3%") << QByteArray("3%25"); + QTest::newRow("13%") << QByteArray("13%") << true << QString("13%") << QByteArray("13%25"); + QTest::newRow("13%!") << QByteArray("13%!") << true << QString("13%!") << QByteArray("13%25!"); + QTest::newRow("13%!!") << QByteArray("13%!!") << true << QString("13%!!") << QByteArray("13%25!!"); + QTest::newRow("13%a") << QByteArray("13%a") << true << QString("13%a") << QByteArray("13%25a"); + QTest::newRow("13%az") << QByteArray("13%az") << true << QString("13%az") << QByteArray("13%25az"); + QTest::newRow("13%25") << QByteArray("13%25") << true << QString("13%") << QByteArray("13%25"); +} + +void tst_QUrl::correctEncodedMistakes() +{ + QFETCH(QByteArray, encodedUrl); + QFETCH(bool, result); + QFETCH(QString, toString); + QFETCH(QByteArray, toEncoded); + + QUrl url = QUrl::fromEncoded(encodedUrl); + QCOMPARE(url.isValid(), result); + if (url.isValid()) { + QCOMPARE(url.toString(), toString); + QCOMPARE(url.toEncoded(), toEncoded); + } +} + +void tst_QUrl::correctDecodedMistakes_data() +{ + QTest::addColumn<QString>("decodedUrl"); + QTest::addColumn<bool>("result"); + QTest::addColumn<QString>("toString"); + QTest::addColumn<QByteArray>("toEncoded"); + + QTest::newRow("%") << QString("%") << true << QString("%") << QByteArray("%25"); + QTest::newRow("3%") << QString("3%") << true << QString("3%") << QByteArray("3%25"); + QTest::newRow("13%") << QString("13%") << true << QString("13%") << QByteArray("13%25"); + QTest::newRow("13%!") << QString("13%!") << true << QString("13%!") << QByteArray("13%25!"); + QTest::newRow("13%!!") << QString("13%!!") << true << QString("13%!!") << QByteArray("13%25!!"); + QTest::newRow("13%a") << QString("13%a") << true << QString("13%a") << QByteArray("13%25a"); + QTest::newRow("13%az") << QString("13%az") << true << QString("13%az") << QByteArray("13%25az"); + QTest::newRow("13%25") << QString("13%25") << true << QString("13%25") << QByteArray("13%2525"); +} + +void tst_QUrl::correctDecodedMistakes() +{ + QFETCH(QString, decodedUrl); + QFETCH(bool, result); + QFETCH(QString, toString); + QFETCH(QByteArray, toEncoded); + + QUrl url(decodedUrl); + QCOMPARE(url.isValid(), result); + if (url.isValid()) { + QCOMPARE(url.toString(), toString); + QCOMPARE(url.toEncoded(), toEncoded); + } +} + +void tst_QUrl::idna_testsuite_data() +{ + QTest::addColumn<int>("numchars"); + QTest::addColumn<ushortarray>("unicode"); + QTest::addColumn<QByteArray>("punycode"); + QTest::addColumn<int>("allowunassigned"); + QTest::addColumn<int>("usestd3asciirules"); + QTest::addColumn<int>("toasciirc"); + QTest::addColumn<int>("tounicoderc"); + + unsigned short d1[] = { 0x0644, 0x064A, 0x0647, 0x0645, 0x0627, 0x0628, 0x062A, 0x0643, + 0x0644, 0x0645, 0x0648, 0x0634, 0x0639, 0x0631, 0x0628, 0x064A, + 0x061F }; + QTest::newRow("Arabic (Egyptian)") << 17 << ushortarray(d1) + << QByteArray(IDNA_ACE_PREFIX "egbpdaj6bu4bxfgehfvwxn") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d2[] = { 0x4ED6, 0x4EEC, 0x4E3A, 0x4EC0, 0x4E48, 0x4E0D, 0x8BF4, 0x4E2D, + 0x6587 }; + QTest::newRow("Chinese (simplified)") << 9 << ushortarray(d2) + << QByteArray(IDNA_ACE_PREFIX "ihqwcrb4cv8a8dqg056pqjye") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d3[] = { 0x4ED6, 0x5011, 0x7232, 0x4EC0, 0x9EBD, 0x4E0D, 0x8AAA, 0x4E2D, + 0x6587 }; + QTest::newRow("Chinese (traditional)") << 9 << ushortarray(d3) + << QByteArray(IDNA_ACE_PREFIX "ihqwctvzc91f659drss3x8bo0yb") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d4[] = { 0x0050, 0x0072, 0x006F, 0x010D, 0x0070, 0x0072, 0x006F, 0x0073, + 0x0074, 0x011B, 0x006E, 0x0065, 0x006D, 0x006C, 0x0075, 0x0076, + 0x00ED, 0x010D, 0x0065, 0x0073, 0x006B, 0x0079 }; + QTest::newRow("Czech") << 22 << ushortarray(d4) + << QByteArray(IDNA_ACE_PREFIX "Proprostnemluvesky-uyb24dma41a") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d5[] = { 0x05DC, 0x05DE, 0x05D4, 0x05D4, 0x05DD, 0x05E4, 0x05E9, 0x05D5, + 0x05D8, 0x05DC, 0x05D0, 0x05DE, 0x05D3, 0x05D1, 0x05E8, 0x05D9, + 0x05DD, 0x05E2, 0x05D1, 0x05E8, 0x05D9, 0x05EA }; + QTest::newRow("Hebrew") << 22 << ushortarray(d5) + << QByteArray(IDNA_ACE_PREFIX "4dbcagdahymbxekheh6e0a7fei0b") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d6[] = { 0x092F, 0x0939, 0x0932, 0x094B, 0x0917, 0x0939, 0x093F, 0x0928, + 0x094D, 0x0926, 0x0940, 0x0915, 0x094D, 0x092F, 0x094B, 0x0902, + 0x0928, 0x0939, 0x0940, 0x0902, 0x092C, 0x094B, 0x0932, 0x0938, + 0x0915, 0x0924, 0x0947, 0x0939, 0x0948, 0x0902 }; + QTest::newRow("Hindi (Devanagari)") << 30 << ushortarray(d6) + << QByteArray(IDNA_ACE_PREFIX "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd") + << 0 << 0 << IDNA_SUCCESS; + + unsigned short d7[] = { 0x306A, 0x305C, 0x307F, 0x3093, 0x306A, 0x65E5, 0x672C, 0x8A9E, + 0x3092, 0x8A71, 0x3057, 0x3066, 0x304F, 0x308C, 0x306A, 0x3044, + 0x306E, 0x304B }; + QTest::newRow("Japanese (kanji and hiragana)") << 18 << ushortarray(d7) + << QByteArray(IDNA_ACE_PREFIX "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa") + << 0 << 0 << IDNA_SUCCESS; + + unsigned short d8[] = { 0x043F, 0x043E, 0x0447, 0x0435, 0x043C, 0x0443, 0x0436, 0x0435, + 0x043E, 0x043D, 0x0438, 0x043D, 0x0435, 0x0433, 0x043E, 0x0432, + 0x043E, 0x0440, 0x044F, 0x0442, 0x043F, 0x043E, 0x0440, 0x0443, + 0x0441, 0x0441, 0x043A, 0x0438 }; + QTest::newRow("Russian (Cyrillic)") << 28 << ushortarray(d8) + << QByteArray(IDNA_ACE_PREFIX "b1abfaaepdrnnbgefbadotcwatmq2g4l") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d9[] = { 0x0050, 0x006F, 0x0072, 0x0071, 0x0075, 0x00E9, 0x006E, 0x006F, + 0x0070, 0x0075, 0x0065, 0x0064, 0x0065, 0x006E, 0x0073, 0x0069, + 0x006D, 0x0070, 0x006C, 0x0065, 0x006D, 0x0065, 0x006E, 0x0074, + 0x0065, 0x0068, 0x0061, 0x0062, 0x006C, 0x0061, 0x0072, 0x0065, + 0x006E, 0x0045, 0x0073, 0x0070, 0x0061, 0x00F1, 0x006F, 0x006C }; + QTest::newRow("Spanish") << 40 << ushortarray(d9) + << QByteArray(IDNA_ACE_PREFIX "PorqunopuedensimplementehablarenEspaol-fmd56a") + << 0 << 0 << IDNA_SUCCESS; + + unsigned short d10[] = { 0x0054, 0x1EA1, 0x0069, 0x0073, 0x0061, 0x006F, 0x0068, 0x1ECD, + 0x006B, 0x0068, 0x00F4, 0x006E, 0x0067, 0x0074, 0x0068, 0x1EC3, + 0x0063, 0x0068, 0x1EC9, 0x006E, 0x00F3, 0x0069, 0x0074, 0x0069, + 0x1EBF, 0x006E, 0x0067, 0x0056, 0x0069, 0x1EC7, 0x0074 }; + QTest::newRow("Vietnamese") << 31 << ushortarray(d10) + << QByteArray(IDNA_ACE_PREFIX "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g") + << 0 << 0 << IDNA_SUCCESS; + + unsigned short d11[] = { 0x0033, 0x5E74, 0x0042, 0x7D44, 0x91D1, 0x516B, 0x5148, 0x751F }; + QTest::newRow("Japanese") << 8 << ushortarray(d11) + << QByteArray(IDNA_ACE_PREFIX "3B-ww4c5e180e575a65lsy2b") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d12[] = { 0x5B89, 0x5BA4, 0x5948, 0x7F8E, 0x6075, 0x002D, 0x0077, 0x0069, + 0x0074, 0x0068, 0x002D, 0x0053, 0x0055, 0x0050, 0x0045, 0x0052, + 0x002D, 0x004D, 0x004F, 0x004E, 0x004B, 0x0045, 0x0059, 0x0053 }; + QTest::newRow("Japanese2") << 24 << ushortarray(d12) + << QByteArray(IDNA_ACE_PREFIX "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n") + << 0 << 0 << IDNA_SUCCESS; + + unsigned short d13[] = { 0x0048, 0x0065, 0x006C, 0x006C, 0x006F, 0x002D, 0x0041, 0x006E, + 0x006F, 0x0074, 0x0068, 0x0065, 0x0072, 0x002D, 0x0057, 0x0061, + 0x0079, 0x002D, 0x305D, 0x308C, 0x305E, 0x308C, 0x306E, 0x5834, + 0x6240 }; + QTest::newRow("Japanese3") << 25 << ushortarray(d13) + << QByteArray(IDNA_ACE_PREFIX "Hello-Another-Way--fc4qua05auwb3674vfr0b") + << 0 << 0 << IDNA_SUCCESS; + + unsigned short d14[] = { 0x3072, 0x3068, 0x3064, 0x5C4B, 0x6839, 0x306E, 0x4E0B, 0x0032 }; + QTest::newRow("Japanese4") << 8 << ushortarray(d14) + << QByteArray(IDNA_ACE_PREFIX "2-u9tlzr9756bt3uc0v") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d15[] = { 0x004D, 0x0061, 0x006A, 0x0069, 0x3067, 0x004B, 0x006F, 0x0069, + 0x3059, 0x308B, 0x0035, 0x79D2, 0x524D }; + QTest::newRow("Japanese5") << 13 << ushortarray(d15) + << QByteArray(IDNA_ACE_PREFIX "MajiKoi5-783gue6qz075azm5e") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d16[] = { 0x30D1, 0x30D5, 0x30A3, 0x30FC, 0x0064, 0x0065, 0x30EB, 0x30F3, 0x30D0 }; + QTest::newRow("Japanese6") << 9 << ushortarray(d16) + << QByteArray(IDNA_ACE_PREFIX "de-jg4avhby1noc0d") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d17[] = { 0x305D, 0x306E, 0x30B9, 0x30D4, 0x30FC, 0x30C9, 0x3067 }; + QTest::newRow("Japanese7") << 7 << ushortarray(d17) + << QByteArray(IDNA_ACE_PREFIX "d9juau41awczczp") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d18[] = { 0x03b5, 0x03bb, 0x03bb, 0x03b7, 0x03bd, 0x03b9, 0x03ba, 0x03ac }; + QTest::newRow("Greek") << 8 << ushortarray(d18) + << QByteArray(IDNA_ACE_PREFIX "hxargifdar") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d19[] = { 0x0062, 0x006f, 0x006e, 0x0121, 0x0075, 0x0073, 0x0061, 0x0127, + 0x0127, 0x0061 }; + QTest::newRow("Maltese (Malti)") << 10 << ushortarray(d19) + << QByteArray(IDNA_ACE_PREFIX "bonusaa-5bb1da") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; + + unsigned short d20[] = {0x043f, 0x043e, 0x0447, 0x0435, 0x043c, 0x0443, 0x0436, 0x0435, + 0x043e, 0x043d, 0x0438, 0x043d, 0x0435, 0x0433, 0x043e, 0x0432, + 0x043e, 0x0440, 0x044f, 0x0442, 0x043f, 0x043e, 0x0440, 0x0443, + 0x0441, 0x0441, 0x043a, 0x0438 }; + QTest::newRow("Russian (Cyrillic)") << 28 << ushortarray(d20) + << QByteArray(IDNA_ACE_PREFIX "b1abfaaepdrnnbgefbadotcwatmq2g4l") + << 0 << 0 << IDNA_SUCCESS << IDNA_SUCCESS; +} + +void tst_QUrl::idna_testsuite() +{ + QFETCH(int, numchars); + QFETCH(ushortarray, unicode); + QFETCH(QByteArray, punycode); + + QString s = QString::fromUtf16(unicode.points, numchars); + QCOMPARE(punycode, QUrl::toPunycode(s)); +} + +void tst_QUrl::nameprep_testsuite_data() +{ + QTest::addColumn<QString>("in"); + QTest::addColumn<QString>("out"); + QTest::addColumn<QString>("profile"); + QTest::addColumn<int>("flags"); + QTest::addColumn<int>("rc"); + + QTest::newRow("Map to nothing") + << QString::fromUtf8("foo\xC2\xAD\xCD\x8F\xE1\xA0\x86\xE1\xA0\x8B" + "bar""\xE2\x80\x8B\xE2\x81\xA0""baz\xEF\xB8\x80\xEF\xB8\x88" + "\xEF\xB8\x8F\xEF\xBB\xBF") + << QString::fromUtf8("foobarbaz") + << QString() << 0 << 0; + + QTest::newRow("Case folding ASCII U+0043 U+0041 U+0046 U+0045") + << QString::fromUtf8("CAFE") + << QString::fromUtf8("cafe") + << QString() << 0 << 0; + + QTest::newRow("Case folding 8bit U+00DF (german sharp s)") + << QString::fromUtf8("\xC3\x9F") + << QString("ss") + << QString() << 0 << 0; + + QTest::newRow("Case folding U+0130 (turkish capital I with dot)") + << QString::fromUtf8("\xC4\xB0") + << QString::fromUtf8("i\xcc\x87") + << QString() << 0 << 0; + + QTest::newRow("Case folding multibyte U+0143 U+037A") + << QString::fromUtf8("\xC5\x83\xCD\xBA") + << QString::fromUtf8("\xC5\x84 \xCE\xB9") + << QString() << 0 << 0; + + QTest::newRow("Case folding U+2121 U+33C6 U+1D7BB") + << QString::fromUtf8("\xE2\x84\xA1\xE3\x8F\x86\xF0\x9D\x9E\xBB") + << QString::fromUtf8("telc\xE2\x88\x95""kg\xCF\x83") + << QString() << 0 << 0; + + QTest::newRow("Normalization of U+006a U+030c U+00A0 U+00AA") + << QString::fromUtf8("\x6A\xCC\x8C\xC2\xA0\xC2\xAA") + << QString::fromUtf8("\xC7\xB0 a") + << QString() << 0 << 0; + + QTest::newRow("Case folding U+1FB7 and normalization") + << QString::fromUtf8("\xE1\xBE\xB7") + << QString::fromUtf8("\xE1\xBE\xB6\xCE\xB9") + << QString() << 0 << 0; + + QTest::newRow("Self-reverting case folding U+01F0 and normalization") +// << QString::fromUtf8("\xC7\xF0") ### typo in the original testsuite + << QString::fromUtf8("\xC7\xB0") + << QString::fromUtf8("\xC7\xB0") + << QString() << 0 << 0; + + QTest::newRow("Self-reverting case folding U+0390 and normalization") + << QString::fromUtf8("\xCE\x90") + << QString::fromUtf8("\xCE\x90") + << QString() << 0 << 0; + + QTest::newRow("Self-reverting case folding U+03B0 and normalization") + << QString::fromUtf8("\xCE\xB0") + << QString::fromUtf8("\xCE\xB0") + << QString() << 0 << 0; + + QTest::newRow("Self-reverting case folding U+1E96 and normalization") + << QString::fromUtf8("\xE1\xBA\x96") + << QString::fromUtf8("\xE1\xBA\x96") + << QString() << 0 << 0; + + QTest::newRow("Self-reverting case folding U+1F56 and normalization") + << QString::fromUtf8("\xE1\xBD\x96") + << QString::fromUtf8("\xE1\xBD\x96") + << QString() << 0 << 0; + + QTest::newRow("ASCII space character U+0020") + << QString::fromUtf8("\x20") + << QString::fromUtf8("\x20") + << QString() << 0 << 0; + + QTest::newRow("Non-ASCII 8bit space character U+00A0") + << QString::fromUtf8("\xC2\xA0") + << QString::fromUtf8("\x20") + << QString() << 0 << 0; + + QTest::newRow("Non-ASCII multibyte space character U+1680") + << QString::fromUtf8("\xE1\x9A\x80") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Non-ASCII multibyte space character U+2000") + << QString::fromUtf8("\xE2\x80\x80") + << QString::fromUtf8("\x20") + << QString() << 0 << 0; + + QTest::newRow("Zero Width Space U+200b") + << QString::fromUtf8("\xE2\x80\x8b") + << QString() + << QString() << 0 << 0; + + QTest::newRow("Non-ASCII multibyte space character U+3000") + << QString::fromUtf8("\xE3\x80\x80") + << QString::fromUtf8("\x20") + << QString() << 0 << 0; + + QTest::newRow("ASCII control characters U+0010 U+007F") + << QString::fromUtf8("\x10\x7F") + << QString::fromUtf8("\x10\x7F") + << QString() << 0 << 0; + + QTest::newRow("Non-ASCII 8bit control character U+0085") + << QString::fromUtf8("\xC2\x85") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Non-ASCII multibyte control character U+180E") + << QString::fromUtf8("\xE1\xA0\x8E") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Zero Width No-Break Space U+FEFF") + << QString::fromUtf8("\xEF\xBB\xBF") + << QString() + << QString() << 0 << 0; + + QTest::newRow("Non-ASCII control character U+1D175") + << QString::fromUtf8("\xF0\x9D\x85\xB5") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Plane 0 private use character U+F123") + << QString::fromUtf8("\xEF\x84\xA3") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Plane 15 private use character U+F1234") + << QString::fromUtf8("\xF3\xB1\x88\xB4") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Plane 16 private use character U+10F234") + << QString::fromUtf8("\xF4\x8F\x88\xB4") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Non-character code point U+8FFFE") + << QString::fromUtf8("\xF2\x8F\xBF\xBE") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Non-character code point U+10FFFF") + << QString::fromUtf8("\xF4\x8F\xBF\xBF") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Surrogate code U+DF42") + << QString::fromUtf8("\xED\xBD\x82") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Non-plain text character U+FFFD") + << QString::fromUtf8("\xEF\xBF\xBD") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Ideographic description character U+2FF5") + << QString::fromUtf8("\xE2\xBF\xB5") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Display property character U+0341") + << QString::fromUtf8("\xCD\x81") + << QString::fromUtf8("\xCC\x81") + << QString() << 0 << 0; + + QTest::newRow("Left-to-right mark U+200E") + << QString::fromUtf8("\xE2\x80\x8E") + << QString::fromUtf8("\xCC\x81") + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Deprecated U+202A") + << QString::fromUtf8("\xE2\x80\xAA") + << QString::fromUtf8("\xCC\x81") + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Language tagging character U+E0001") + << QString::fromUtf8("\xF3\xA0\x80\x81") + << QString::fromUtf8("\xCC\x81") + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Language tagging character U+E0042") + << QString::fromUtf8("\xF3\xA0\x81\x82") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_CONTAINS_PROHIBITED; + + QTest::newRow("Bidi: RandALCat character U+05BE and LCat characters") + << QString::fromUtf8("foo\xD6\xBE""bar") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_BIDI_BOTH_L_AND_RAL; + + QTest::newRow("Bidi: RandALCat character U+FD50 and LCat characters") + << QString::fromUtf8("foo\xEF\xB5\x90""bar") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_BIDI_BOTH_L_AND_RAL; + + QTest::newRow("Bidi: RandALCat character U+FB38 and LCat characters") + << QString::fromUtf8("foo\xEF\xB9\xB6""bar") + << QString::fromUtf8("foo \xd9\x8e""bar") + << QString() << 0 << 0; + + QTest::newRow("Bidi: RandALCat without trailing RandALCat U+0627 U+0031") + << QString::fromUtf8("\xD8\xA7\x31") + << QString() + << QString("Nameprep") << 0 << STRINGPREP_BIDI_LEADTRAIL_NOT_RAL; + + QTest::newRow("Bidi: RandALCat character U+0627 U+0031 U+0628") + << QString::fromUtf8("\xD8\xA7\x31\xD8\xA8") + << QString::fromUtf8("\xD8\xA7\x31\xD8\xA8") + << QString() << 0 << 0; + + QTest::newRow("Unassigned code point U+E0002") + << QString::fromUtf8("\xF3\xA0\x80\x82") + << QString() + << QString("Nameprep") << STRINGPREP_NO_UNASSIGNED << STRINGPREP_CONTAINS_UNASSIGNED; + + QTest::newRow("Larger test (shrinking)") + << QString::fromUtf8("X\xC2\xAD\xC3\x9F\xC4\xB0\xE2\x84\xA1\x6a\xcc\x8c\xc2\xa0\xc2" + "\xaa\xce\xb0\xe2\x80\x80") + << QString::fromUtf8("xssi\xcc\x87""tel\xc7\xb0 a\xce\xb0 ") + << QString("Nameprep") << 0 << 0; + + QTest::newRow("Larger test (expanding)") + << QString::fromUtf8("X\xC3\x9F\xe3\x8c\x96\xC4\xB0\xE2\x84\xA1\xE2\x92\x9F\xE3\x8c\x80") + << QString::fromUtf8("xss\xe3\x82\xad\xe3\x83\xad\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\x88" + "\xe3\x83\xab""i\xcc\x87""tel\x28""d\x29\xe3\x82\xa2\xe3\x83\x91" + "\xe3\x83\xbc\xe3\x83\x88") + << QString() << 0 << 0; +} + +#ifdef QT_BUILD_INTERNAL +QT_BEGIN_NAMESPACE +extern void qt_nameprep(QString *source, int from); +extern bool qt_check_std3rules(const QChar *, int); +QT_END_NAMESPACE +#endif + +void tst_QUrl::nameprep_testsuite() +{ +#ifdef QT_BUILD_INTERNAL + QFETCH(QString, in); + QFETCH(QString, out); + QFETCH(QString, profile); + + QEXPECT_FAIL("Left-to-right mark U+200E", + "Investigate further", Continue); + QEXPECT_FAIL("Deprecated U+202A", + "Investigate further", Continue); + QEXPECT_FAIL("Language tagging character U+E0001", + "Investigate further", Continue); + qt_nameprep(&in, 0); + QCOMPARE(in, out); +#endif +} + +void tst_QUrl::nameprep_highcodes_data() +{ + QTest::addColumn<QString>("in"); + QTest::addColumn<QString>("out"); + QTest::addColumn<QString>("profile"); + QTest::addColumn<int>("flags"); + QTest::addColumn<int>("rc"); + + { + QChar st[] = { '-', 0xd801, 0xdc1d, 'a' }; + QChar se[] = { '-', 0xd801, 0xdc45, 'a' }; + QTest::newRow("highcodes (U+1041D)") + << QString(st, sizeof(st)/sizeof(st[0])) + << QString(se, sizeof(se)/sizeof(se[0])) + << QString() << 0 << 0; + } + { + QChar st[] = { 0x011C, 0xd835, 0xdf6e, 0x0110 }; + QChar se[] = { 0x011D, 0x03C9, 0x0111 }; + QTest::newRow("highcodes (U+1D76E)") + << QString(st, sizeof(st)/sizeof(st[0])) + << QString(se, sizeof(se)/sizeof(se[0])) + << QString() << 0 << 0; + } + { + QChar st[] = { 'D', 0xdb40, 0xdc20, 'o', 0xd834, 0xdd7a, '\'', 0x2060, 'h' }; + QChar se[] = { 'd', 'o', '\'', 'h' }; + QTest::newRow("highcodes (D, U+E0020, o, U+1D17A, ', U+2060, h)") + << QString(st, sizeof(st)/sizeof(st[0])) + << QString(se, sizeof(se)/sizeof(se[0])) + << QString() << 0 << 0; + } +} + +void tst_QUrl::nameprep_highcodes() +{ +#ifdef QT_BUILD_INTERNAL + QFETCH(QString, in); + QFETCH(QString, out); + QFETCH(QString, profile); + + qt_nameprep(&in, 0); + QCOMPARE(in, out); +#endif +} + +void tst_QUrl::ace_testsuite_data() +{ + QTest::addColumn<QString>("in"); + QTest::addColumn<QString>("toace"); + QTest::addColumn<QString>("fromace"); + QTest::addColumn<QString>("unicode"); + + QTest::newRow("ascii-lower") << "fluke" << "fluke" << "fluke" << "fluke"; + QTest::newRow("ascii-mixed") << "FLuke" << "fluke" << "fluke" << "fluke"; + QTest::newRow("ascii-upper") << "FLUKE" << "fluke" << "fluke" << "fluke"; + + QTest::newRow("asciifolded") << QString::fromLatin1("stra\337e") << "strasse" << "." << "strasse"; + QTest::newRow("asciifolded-dotcom") << QString::fromLatin1("stra\337e.example.com") << "strasse.example.com" << "." << "strasse.example.com"; + QTest::newRow("greek-mu") << QString::fromLatin1("\265V") + <<"xn--v-lmb" + << "." + << QString::fromUtf8("\316\274v"); + + QTest::newRow("non-ascii-lower") << QString::fromLatin1("alqualond\353") + << "xn--alqualond-34a" + << "." + << QString::fromLatin1("alqualond\353"); + QTest::newRow("non-ascii-mixed") << QString::fromLatin1("Alqualond\353") + << "xn--alqualond-34a" + << "." + << QString::fromLatin1("alqualond\353"); + QTest::newRow("non-ascii-upper") << QString::fromLatin1("ALQUALOND\313") + << "xn--alqualond-34a" + << "." + << QString::fromLatin1("alqualond\353"); + + QTest::newRow("idn-lower") << "xn--alqualond-34a" << "xn--alqualond-34a" + << QString::fromLatin1("alqualond\353") + << QString::fromLatin1("alqualond\353"); + QTest::newRow("idn-mixed") << "Xn--alqualond-34a" << "xn--alqualond-34a" + << QString::fromLatin1("alqualond\353") + << QString::fromLatin1("alqualond\353"); + QTest::newRow("idn-mixed2") << "XN--alqualond-34a" << "xn--alqualond-34a" + << QString::fromLatin1("alqualond\353") + << QString::fromLatin1("alqualond\353"); + QTest::newRow("idn-mixed3") << "xn--ALQUALOND-34a" << "xn--alqualond-34a" + << QString::fromLatin1("alqualond\353") + << QString::fromLatin1("alqualond\353"); + QTest::newRow("idn-mixed4") << "xn--alqualond-34A" << "xn--alqualond-34a" + << QString::fromLatin1("alqualond\353") + << QString::fromLatin1("alqualond\353"); + QTest::newRow("idn-upper") << "XN--ALQUALOND-34A" << "xn--alqualond-34a" + << QString::fromLatin1("alqualond\353") + << QString::fromLatin1("alqualond\353"); + + QTest::newRow("separator-3002") << QString::fromUtf8("example\343\200\202com") + << "example.com" << "." << "example.com"; + + QString egyptianIDN = + QString::fromUtf8("\331\210\330\262\330\247\330\261\330\251\055\330\247\331\204\330" + "\243\330\252\330\265\330\247\331\204\330\247\330\252.\331\205" + "\330\265\330\261"); + QTest::newRow("egyptian-tld-ace") + << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" + << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" + << "." + << egyptianIDN; + QTest::newRow("egyptian-tld-unicode") + << egyptianIDN + << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" + << "." + << egyptianIDN; + QTest::newRow("egyptian-tld-mix1") + << QString::fromUtf8("\331\210\330\262\330\247\330\261\330\251\055\330\247\331\204\330" + "\243\330\252\330\265\330\247\331\204\330\247\330\252.xn--wgbh1c") + << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" + << "." + << egyptianIDN; + QTest::newRow("egyptian-tld-mix2") + << QString::fromUtf8("xn----rmckbbajlc6dj7bxne2c.\331\205\330\265\330\261") + << "xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c" + << "." + << egyptianIDN; +} + +void tst_QUrl::ace_testsuite() +{ + static const char canonsuffix[] = ".troll.no"; + QFETCH(QString, in); + QFETCH(QString, toace); + QFETCH(QString, fromace); + QFETCH(QString, unicode); + + const char *suffix = canonsuffix; + if (toace.contains('.')) + suffix = 0; + + QString domain = in + suffix; + QCOMPARE(QString::fromLatin1(QUrl::toAce(domain)), toace + suffix); + if (fromace != ".") + QCOMPARE(QUrl::fromAce(domain.toLatin1()), fromace + suffix); + QCOMPARE(QUrl::fromAce(QUrl::toAce(domain)), unicode + suffix); + + domain = in + (suffix ? ".troll.No" : ""); + QCOMPARE(QString::fromLatin1(QUrl::toAce(domain)), toace + suffix); + if (fromace != ".") + QCOMPARE(QUrl::fromAce(domain.toLatin1()), fromace + suffix); + QCOMPARE(QUrl::fromAce(QUrl::toAce(domain)), unicode + suffix); + + domain = in + (suffix ? ".troll.NO" : ""); + QCOMPARE(QString::fromLatin1(QUrl::toAce(domain)), toace + suffix); + if (fromace != ".") + QCOMPARE(QUrl::fromAce(domain.toLatin1()), fromace + suffix); + QCOMPARE(QUrl::fromAce(QUrl::toAce(domain)), unicode + suffix); +} + +void tst_QUrl::std3violations_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<bool>("validUrl"); + + QTest::newRow("too-long") << "this-domain-is-far-too-long-for-its-own-good-and-should-have-been-limited-to-63-chars" << false; + QTest::newRow("dash-begin") << "-x-foo" << false; + QTest::newRow("dash-end") << "x-foo-" << false; + QTest::newRow("dash-begin-end") << "-foo-" << false; + + QTest::newRow("control") << "\033foo" << false; + QTest::newRow("bang") << "foo!" << false; + QTest::newRow("plus") << "foo+bar" << false; + QTest::newRow("dot") << "foo.bar"; + QTest::newRow("startingdot") << ".bar" << false; + QTest::newRow("startingdot2") << ".example.com" << false; + QTest::newRow("slash") << "foo/bar" << true; + QTest::newRow("colon") << "foo:80" << true; + QTest::newRow("question") << "foo?bar" << true; + QTest::newRow("at") << "foo@bar" << true; + QTest::newRow("backslash") << "foo\\bar" << false; + + // these characters are transformed by NFKC to non-LDH characters + QTest::newRow("dot-like") << QString::fromUtf8("foo\342\200\244bar") << false; // U+2024 ONE DOT LEADER + QTest::newRow("slash-like") << QString::fromUtf8("foo\357\274\217bar") << false; // U+FF0F FULLWIDTH SOLIDUS + + // The following should be invalid but isn't + // the DIVISON SLASH doesn't case-fold to a slash + // is this a problem with RFC 3490? + //QTest::newRow("slash-like2") << QString::fromUtf8("foo\342\210\225bar") << false; // U+2215 DIVISION SLASH +} + +void tst_QUrl::std3violations() +{ + QFETCH(QString, source); + +#ifdef QT_BUILD_INTERNAL + { + QString prepped = source; + qt_nameprep(&prepped, 0); + QVERIFY(!qt_check_std3rules(prepped.constData(), prepped.length())); + } +#endif + + if (source.contains('.')) + return; // this test ends here + + QUrl url; + url.setHost(source); + QVERIFY(url.host().isEmpty()); + + QFETCH(bool, validUrl); + if (validUrl) + return; // test ends here for these cases + + url = QUrl("http://" + source + "/some/path"); + QVERIFY(!url.isValid()); +} + +void tst_QUrl::std3deviations_data() +{ + QTest::addColumn<QString>("source"); + + QTest::newRow("ending-dot") << "example.com."; + QTest::newRow("ending-dot3002") << QString("example.com") + QChar(0x3002); + QTest::newRow("underline") << "foo_bar"; //QTBUG-7434 +} + +void tst_QUrl::std3deviations() +{ + QFETCH(QString, source); + QVERIFY(!QUrl::toAce(source).isEmpty()); + + QUrl url; + url.setHost(source); + QVERIFY(!url.host().isEmpty()); +} + +void tst_QUrl::tldRestrictions_data() +{ + QTest::addColumn<QString>("tld"); + QTest::addColumn<bool>("encode"); + + // current whitelist + QTest::newRow("ac") << QString("ac") << true; + QTest::newRow("at") << QString("at") << true; + QTest::newRow("br") << QString("br") << true; + QTest::newRow("cat") << QString("cat") << true; + QTest::newRow("ch") << QString("ch") << true; + QTest::newRow("cl") << QString("cl") << true; + QTest::newRow("cn") << QString("cn") << true; + QTest::newRow("de") << QString("de") << true; + QTest::newRow("dk") << QString("dk") << true; + QTest::newRow("fi") << QString("fi") << true; + QTest::newRow("hu") << QString("hu") << true; + QTest::newRow("info") << QString("info") << true; + QTest::newRow("io") << QString("io") << true; + QTest::newRow("jp") << QString("jp") << true; + QTest::newRow("kr") << QString("kr") << true; + QTest::newRow("li") << QString("li") << true; + QTest::newRow("lt") << QString("lt") << true; + QTest::newRow("museum") << QString("museum") << true; + QTest::newRow("no") << QString("no") << true; + QTest::newRow("se") << QString("se") << true; + QTest::newRow("sh") << QString("sh") << true; + QTest::newRow("th") << QString("th") << true; + QTest::newRow("tm") << QString("tm") << true; + QTest::newRow("tw") << QString("tw") << true; + QTest::newRow("vn") << QString("vn") << true; + + // known blacklists: + QTest::newRow("com") << QString("com") << false; + QTest::newRow("foo") << QString("foo") << false; +} + +void tst_QUrl::tldRestrictions() +{ + QFETCH(QString, tld); + + // www.brød.tld + QByteArray ascii = "www.xn--brd-1na." + tld.toLatin1(); + QString unicode = QLatin1String("www.br\370d.") + tld; + QString encoded = QUrl::fromAce(ascii); + QTEST(!encoded.contains(".xn--"), "encode"); + QTEST(encoded == unicode, "encode"); + + QUrl url = QUrl::fromEncoded("http://www.xn--brd-1na." + tld.toLatin1()); + QTEST(!url.host().contains(".xn--"), "encode"); + QTEST(url.host() == unicode, "encode"); + + url.setUrl(QLatin1String("http://www.xn--brd-1na.") + tld); + QTEST(!url.host().contains(".xn--"), "encode"); + QTEST(url.host() == unicode, "encode"); + + url.setUrl(QLatin1String("http://www.br\370d.") + tld); + QTEST(!url.host().contains(".xn--"), "encode"); + QTEST(url.host() == unicode, "encode"); + + url = QUrl::fromEncoded("http://www.br%C3%B8d." + tld.toLatin1()); + QTEST(!url.host().contains(".xn--"), "encode"); + QTEST(url.host() == unicode, "encode"); +} + +void tst_QUrl::emptyQueryOrFragment() +{ + QUrl qurl = QUrl::fromEncoded("http://www.kde.org/cgi/test.cgi?", QUrl::TolerantMode); + QCOMPARE(qurl.toEncoded().constData(), "http://www.kde.org/cgi/test.cgi?"); // Empty refs should be preserved + QCOMPARE(qurl.toString(), QString("http://www.kde.org/cgi/test.cgi?")); + qurl = QUrl::fromEncoded("http://www.kde.org/cgi/test.cgi#", QUrl::TolerantMode); + QCOMPARE(qurl.toEncoded().constData(), "http://www.kde.org/cgi/test.cgi#"); + QCOMPARE(qurl.toString(), QString("http://www.kde.org/cgi/test.cgi#")); + + { + // start with an empty one + QUrl url("http://www.foo.bar/baz"); + QVERIFY(!url.hasFragment()); + QVERIFY(url.fragment().isNull()); + + // add fragment + url.setFragment(QLatin1String("abc")); + QVERIFY(url.hasFragment()); + QCOMPARE(url.fragment(), QString(QLatin1String("abc"))); + QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz#abc"))); + + // remove fragment + url.setFragment(QString()); + QVERIFY(!url.hasFragment()); + QVERIFY(url.fragment().isNull()); + QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz"))); + + // add empty fragment + url.setFragment(QLatin1String("")); + QVERIFY(url.hasFragment()); + QVERIFY(url.fragment().isEmpty()); + QVERIFY(!url.fragment().isNull()); + QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz#"))); + } + + { + // start with an empty one + QUrl url("http://www.foo.bar/baz"); + QVERIFY(!url.hasQuery()); + QVERIFY(url.encodedQuery().isNull()); + + // add encodedQuery + url.setEncodedQuery("abc=def"); + QVERIFY(url.hasQuery()); + QCOMPARE(QString(url.encodedQuery()), QString(QLatin1String("abc=def"))); + QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?abc=def"))); + + // remove encodedQuery + url.setEncodedQuery(0); + QVERIFY(!url.hasQuery()); + QVERIFY(url.encodedQuery().isNull()); + QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz"))); + + // add empty encodedQuery + url.setEncodedQuery(""); + QVERIFY(url.hasQuery()); + QVERIFY(url.encodedQuery().isEmpty()); + QVERIFY(!url.encodedQuery().isNull()); + QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?"))); + } +} + +void tst_QUrl::hasFragment_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<bool>("trueFalse"); + + QTest::newRow("no fragment") << "http://www.foo.bar" << false; + + QTest::newRow("empty fragment") << "http://www.foo.bar#" << true; + QTest::newRow("empty fragment 2") << "http://www.foo.bar/#" << true; + + QTest::newRow("fragment") << "http://www.foo.bar#baz" << true; + QTest::newRow("fragment2") << "http://www.foo.bar/#baz" << true; + + QTest::newRow("%23") << "http://www.foo.bar/%23" << false; + QTest::newRow("%23-and-something") << "http://www.foo.bar/%23baz" << false; +} + +void tst_QUrl::hasFragment() +{ + QFETCH(QString, url); + QFETCH(bool, trueFalse); + + QUrl qurl(url); + QCOMPARE(qurl.hasFragment(), trueFalse); + QCOMPARE(qurl.fragment().isNull(), !trueFalse); +} + +void tst_QUrl::setEncodedFragment_data() +{ + QTest::addColumn<QByteArray>("base"); + QTest::addColumn<QByteArray>("fragment"); + QTest::addColumn<QByteArray>("expected"); + + typedef QByteArray BA; + QTest::newRow("empty") << BA("http://www.kde.org") << BA("") << BA("http://www.kde.org#"); + QTest::newRow("basic test") << BA("http://www.kde.org") << BA("abc") << BA("http://www.kde.org#abc"); + QTest::newRow("initial url has fragment") << BA("http://www.kde.org#old") << BA("new") << BA("http://www.kde.org#new"); + QTest::newRow("encoded fragment") << BA("http://www.kde.org") << BA("a%20c") << BA("http://www.kde.org#a%20c"); + QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a#b"); +} + +void tst_QUrl::setEncodedFragment() +{ + QFETCH(QByteArray, base); + QFETCH(QByteArray, fragment); + QFETCH(QByteArray, expected); + QUrl u; + u.setEncodedUrl(base, QUrl::TolerantMode); + QVERIFY(u.isValid()); + u.setEncodedFragment(fragment); + QVERIFY(u.isValid()); + QVERIFY(u.hasFragment()); + QCOMPARE(QString::fromLatin1(u.toEncoded()), QString::fromLatin1(expected)); +} + +void tst_QUrl::fromEncoded() +{ + QUrl qurl2 = QUrl::fromEncoded("print:/specials/Print%20To%20File%20(PDF%252FAcrobat)", QUrl::TolerantMode); + QCOMPARE(qurl2.path(), QString::fromLatin1("/specials/Print To File (PDF%2FAcrobat)")); + QCOMPARE(QFileInfo(qurl2.path()).fileName(), QString::fromLatin1("Print To File (PDF%2FAcrobat)")); + QCOMPARE(qurl2.toEncoded().constData(), "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)"); + + QUrl qurl = QUrl::fromEncoded("http://\303\244.de"); + QVERIFY(qurl.isValid()); + QCOMPARE(qurl.toEncoded().constData(), "http://xn--4ca.de"); + + QUrl qurltest(QUrl::fromPercentEncoding("http://\303\244.de")); + QVERIFY(qurltest.isValid()); + + QUrl qurl_newline_1 = QUrl::fromEncoded("http://www.foo.bar/foo/bar\ngnork", QUrl::TolerantMode); + QVERIFY(qurl_newline_1.isValid()); + QCOMPARE(qurl_newline_1.toEncoded().constData(), "http://www.foo.bar/foo/bar%0Agnork"); +} + +void tst_QUrl::stripTrailingSlash() +{ + QUrl u1( "ftp://ftp.de.kde.org/dir" ); + QUrl u2( "ftp://ftp.de.kde.org/dir/" ); + QUrl::FormattingOptions options = QUrl::None; + options |= QUrl::StripTrailingSlash; + QString str1 = u1.toString(options); + QString str2 = u2.toString(options); + QCOMPARE( str1, u1.toString() ); + QCOMPARE( str2, u1.toString() ); + bool same = str1 == str2; + QVERIFY( same ); +} + +void tst_QUrl::hosts_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<QString>("host"); + + QTest::newRow("empty") << QString("") << QString(""); + QTest::newRow("empty1") << QString("file:///file") << QString(""); + QTest::newRow("empty2") << QString("file:/file") << QString(""); + QTest::newRow("empty3") << QString("http:///file") << QString(""); + QTest::newRow("empty4") << QString("http:/file") << QString(""); + + // numeric hostnames + QTest::newRow("http://123/") << QString("http://123/") << QString("123"); + QTest::newRow("http://456/") << QString("http://456/") << QString("456"); + QTest::newRow("http://1000/") << QString("http://1000/") << QString("1000"); + + // IP literals + QTest::newRow("normal-ip-literal") << QString("http://1.2.3.4") << QString("1.2.3.4"); + QTest::newRow("normal-ip-literal-with-port") << QString("http://1.2.3.4:80") + << QString("1.2.3.4"); + QTest::newRow("ipv6-literal") << QString("http://[::1]") << QString("::1"); + QTest::newRow("ipv6-literal-with-port") << QString("http://[::1]:80") << QString("::1"); + QTest::newRow("long-ipv6-literal") << QString("http://[2001:200:0:8002:203:47ff:fea5:3085]") + << QString("2001:200:0:8002:203:47ff:fea5:3085"); + QTest::newRow("long-ipv6-literal-with-port") << QString("http://[2001:200:0:8002:203:47ff:fea5:3085]:80") + << QString("2001:200:0:8002:203:47ff:fea5:3085"); + QTest::newRow("ipv6-literal-v4compat") << QString("http://[::255.254.253.252]") + << QString("::255.254.253.252"); + QTest::newRow("ipv6-literal-v4compat-2") << QString("http://[1000::ffff:127.128.129.1]") + << QString("1000::ffff:127.128.129.1"); + QTest::newRow("long-ipv6-literal-v4compat") << QString("http://[fec0:8000::8002:1000:ffff:200.100.50.250]") + << QString("fec0:8000::8002:1000:ffff:200.100.50.250"); + QTest::newRow("longer-ipv6-literal-v4compat") << QString("http://[fec0:8000:4000:8002:1000:ffff:200.100.50.250]") + << QString("fec0:8000:4000:8002:1000:ffff:200.100.50.250"); + +#if 0 + // this is actually invalid + QTest::newRow("mac-literal") << QString("obex://[00:30:1b:b7:21:fb]") + << QString("00:30:1b:b7:21:fb"); +#endif + + // normal hostnames + QTest::newRow("normal") << QString("http://intern") << QString("intern"); + QTest::newRow("normal2") << QString("http://qt.nokia.com") << QString("qt.nokia.com"); + + // IDN hostnames + QTest::newRow("idn") << QString(QLatin1String("http://\345r.no")) << QString(QLatin1String("\345r.no")); + QTest::newRow("idn-ace") << QString("http://xn--r-1fa.no") << QString(QLatin1String("\345r.no")); +} + +void tst_QUrl::hosts() +{ + QFETCH(QString, url); + + QTEST(QUrl(url).host(), "host"); +} + +void tst_QUrl::setPort() +{ + { + QUrl url; + QVERIFY(url.toString().isEmpty()); + url.setPort(80); + QCOMPARE(url.port(), 80); + QCOMPARE(url.toString(), QString::fromLatin1("//:80")); + url.setPort(-1); + QCOMPARE(url.port(), -1); + QVERIFY(url.toString().isEmpty()); + url.setPort(80); + QTest::ignoreMessage(QtWarningMsg, "QUrl::setPort: Out of range"); + url.setPort(65536); + QCOMPARE(url.port(), -1); + } +} + +void tst_QUrl::toEncoded_data() +{ + QTest::addColumn<QByteArray>("url"); + QTest::addColumn<QUrl::FormattingOptions>("options"); + QTest::addColumn<QByteArray>("encoded"); + QTest::newRow("file:///dir/") << QByteArray("file:///dir/") + << QUrl::FormattingOptions(QUrl::StripTrailingSlash) + << QByteArray("file:///dir"); +} + +void tst_QUrl::toEncoded() +{ + QFETCH(QByteArray, url); + QFETCH(QUrl::FormattingOptions, options); + QFETCH(QByteArray, encoded); + + QCOMPARE(QUrl::fromEncoded(url).toEncoded(options), encoded); +} + +void tst_QUrl::setAuthority_data() +{ + QTest::addColumn<QString>("authority"); + QTest::addColumn<QString>("url"); + QTest::newRow("Plain auth") << QString("62.70.27.22:21") << QString("//62.70.27.22:21"); + QTest::newRow("Yet another plain auth") << QString("192.168.1.1:21") << QString("//192.168.1.1:21"); + QTest::newRow("Auth without port") << QString("192.168.1.1") << QString("//192.168.1.1"); + QTest::newRow("Auth w/full hostname without port") << QString("shusaku.troll.no") << QString("//shusaku.troll.no"); + QTest::newRow("Auth w/hostname without port") << QString("shusaku") << QString("//shusaku"); + QTest::newRow("Auth w/full hostname that ends with number, without port") << QString("shusaku.troll.no.2") << QString("//shusaku.troll.no.2"); + QTest::newRow("Auth w/hostname that ends with number, without port") << QString("shusaku2") << QString("//shusaku2"); + QTest::newRow("Empty auth") << QString() << QString(); +} + +void tst_QUrl::setAuthority() +{ + QUrl u; + QFETCH(QString, authority); + QFETCH(QString, url); + u.setAuthority(authority); + QCOMPARE(u.toString(), url); +} + +void tst_QUrl::errorString() +{ + QUrl u = QUrl::fromEncoded("http://strange<username>@bad_hostname/", QUrl::StrictMode); + QVERIFY(!u.isValid()); + QString errorString = "Invalid URL \"http://strange<username>@bad_hostname/\": " + "error at position 14: expected end of URL, but found '<'"; + QCOMPARE(u.errorString(), errorString); + + QUrl v; + errorString = "Invalid URL \"\": "; + QCOMPARE(v.errorString(), errorString); +} + +void tst_QUrl::clear() +{ + QUrl url("a"); + QUrl url2("a"); + QCOMPARE(url, url2); + url.clear(); + QVERIFY(url != url2); +} + +void tst_QUrl::binaryData_data() +{ + QTest::addColumn<QString>("url"); + QTest::newRow("username") << "http://%01%0D%0A%7F@foo/"; + QTest::newRow("username-at") << "http://abc%40_def@foo/"; + QTest::newRow("username-nul") << "http://abc%00_def@foo/"; + QTest::newRow("username-colon") << "http://abc%3A_def@foo/"; + QTest::newRow("username-nonutf8") << "http://abc%E1_def@foo/"; + + QTest::newRow("password") << "http://user:%01%0D%0A%7F@foo/"; + QTest::newRow("password-at") << "http://user:abc%40_def@foo/"; + QTest::newRow("password-nul") << "http://user:abc%00_def@foo/"; + QTest::newRow("password-nonutf8") << "http://user:abc%E1_def@foo/"; + + QTest::newRow("file") << "http://foo/%01%0D%0A%7F"; + QTest::newRow("file-nul") << "http://foo/abc%00_def"; + QTest::newRow("file-hash") << "http://foo/abc%23_def"; + QTest::newRow("file-question") << "http://foo/abc%3F_def"; + QTest::newRow("file-nonutf8") << "http://foo/abc%E1_def"; + QTest::newRow("file-slash") << "http://foo/abc%2f_def"; + + QTest::newRow("ref") << "http://foo/file#a%01%0D%0A%7F"; + QTest::newRow("ref-nul") << "http://foo/file#abc%00_def"; + QTest::newRow("ref-question") << "http://foo/file#abc?_def"; + QTest::newRow("ref-nonutf8") << "http://foo/file#abc%E1_def"; + + QTest::newRow("query-value") << "http://foo/query?foo=%01%0D%0A%7F"; + QTest::newRow("query-value-nul") << "http://foo/query?foo=abc%00_def"; + QTest::newRow("query-value-nonutf8") << "http://foo/query?foo=abc%E1_def"; + + QTest::newRow("query-name") << "http://foo/query/a%01%0D%0A%7Fz=foo"; + QTest::newRow("query-name-nul") << "http://foo/query/abc%00_def=foo"; + QTest::newRow("query-name-nonutf8") << "http://foo/query/abc%E1_def=foo"; +} + +void tst_QUrl::binaryData() +{ + QFETCH(QString, url); + QUrl u = QUrl::fromEncoded(url.toUtf8()); + + QVERIFY(u.isValid()); + QVERIFY(!u.isEmpty()); + + QString url2 = QString::fromUtf8(u.toEncoded()); + //QCOMPARE(url2.length(), url.length()); + QCOMPARE(url2, url); +} + +void tst_QUrl::fromUserInput_data() +{ + // + // most of this test is: + // Copyright (C) Research In Motion Limited 2009. All rights reserved. + // Distributed under the BSD license. + // See qurl.cpp + // + + QTest::addColumn<QString>("string"); + QTest::addColumn<QUrl>("guessUrlFromString"); + + // Null + QTest::newRow("null") << QString() << QUrl(); + + // File + QDirIterator it(QDir::homePath()); + int c = 0; + while (it.hasNext()) { + it.next(); + QTest::newRow(QString("file-%1").arg(c++).toLatin1()) << it.filePath() << QUrl::fromLocalFile(it.filePath()); + } + + // basic latin1 + QTest::newRow("unicode-0") << QString::fromUtf8("\xc3\xa5.com/") << QUrl::fromEncoded(QString::fromUtf8("http://\xc3\xa5.com/").toUtf8(), QUrl::TolerantMode); + QTest::newRow("unicode-0b") << QString::fromUtf8("\xc3\xa5.com/") << QUrl::fromEncoded("http://%C3%A5.com/", QUrl::TolerantMode); + QTest::newRow("unicode-0c") << QString::fromUtf8("\xc3\xa5.com/") << QUrl::fromEncoded("http://xn--5ca.com/", QUrl::TolerantMode); + // unicode + QTest::newRow("unicode-1") << QString::fromUtf8("\xce\xbb.com/") << QUrl::fromEncoded(QString::fromUtf8("http://\xce\xbb.com/").toUtf8(), QUrl::TolerantMode); + QTest::newRow("unicode-1b") << QString::fromUtf8("\xce\xbb.com/") << QUrl::fromEncoded("http://%CE%BB.com/", QUrl::TolerantMode); + QTest::newRow("unicode-1c") << QString::fromUtf8("\xce\xbb.com/") << QUrl::fromEncoded("http://xn--wxa.com/", QUrl::TolerantMode); + + // no scheme + QTest::newRow("add scheme-0") << "example.org" << QUrl("http://example.org"); + QTest::newRow("add scheme-1") << "www.example.org" << QUrl("http://www.example.org"); + QTest::newRow("add scheme-2") << "ftp.example.org" << QUrl("ftp://ftp.example.org"); + QTest::newRow("add scheme-3") << "hostname" << QUrl("http://hostname"); + + // QUrl's tolerant parser should already handle this + QTest::newRow("not-encoded-0") << "http://example.org/test page.html" << QUrl::fromEncoded("http://example.org/test%20page.html"); + + // Make sure the :80, i.e. port doesn't screw anything up + QUrl portUrl("http://example.org"); + portUrl.setPort(80); + QTest::newRow("port-0") << "example.org:80" << portUrl; + QTest::newRow("port-1") << "http://example.org:80" << portUrl; + portUrl.setPath("path"); + QTest::newRow("port-1") << "example.org:80/path" << portUrl; + QTest::newRow("port-1") << "http://example.org:80/path" << portUrl; + + // mailto doesn't have a ://, but is valid + QUrl mailto("ben@example.net"); + mailto.setScheme("mailto"); + QTest::newRow("mailto") << "mailto:ben@example.net" << mailto; + + // misc + QTest::newRow("localhost-1") << "localhost:80" << QUrl("http://localhost:80"); + QTest::newRow("spaces-0") << " http://example.org/test page.html " << QUrl("http://example.org/test%20page.html"); + QTest::newRow("trash-0") << "example.org/test?someData=42%&someOtherData=abcde#anchor" << QUrl::fromEncoded("http://example.org/test?someData=42%25&someOtherData=abcde#anchor"); + QTest::newRow("other-scheme-0") << "spotify:track:0hO542doVbfGDAGQULMORT" << QUrl("spotify:track:0hO542doVbfGDAGQULMORT"); + QTest::newRow("other-scheme-1") << "weirdscheme:80:otherstuff" << QUrl("weirdscheme:80:otherstuff"); + + // FYI: The scheme in the resulting url user + QUrl authUrl("user:pass@domain.com"); + QTest::newRow("misc-1") << "user:pass@domain.com" << authUrl; +} + +void tst_QUrl::fromUserInput() +{ + QFETCH(QString, string); + QFETCH(QUrl, guessUrlFromString); + + QUrl url = QUrl::fromUserInput(string); + QCOMPARE(url, guessUrlFromString); +} + +void tst_QUrl::task_199967() +{ + { + QUrl url; + url.setEncodedUrl("LABEL=USB_STICK", QUrl::TolerantMode); + QVERIFY( url.isValid() ); + QCOMPARE( url.path(), QString("LABEL=USB_STICK") ); + QVERIFY( !url.isEmpty() ); + } + { + QUrl url; + url.setEncodedUrl("LABEL=USB_STICK", QUrl::TolerantMode); + QVERIFY( url.isValid() ); + QVERIFY( !url.isEmpty() ); + QCOMPARE( url.path(), QString("LABEL=USB_STICK") ); + } +} + +void tst_QUrl::task_240612() +{ + QUrl url; + url.setEncodedPath("test.txt"); + url.setHost("example.com"); + + QCOMPARE(url.toEncoded().constData(), "//example.com/test.txt"); + + url.path(); + QCOMPARE(url.toEncoded().constData(), "//example.com/test.txt"); +} + +void tst_QUrl::resolvedWithAbsoluteSchemes() const +{ + QFETCH(QUrl, base); + QFETCH(QUrl, relative); + QFETCH(QUrl, expected); + + /* Check our input. */ + QVERIFY(relative.isValid()); + QVERIFY(base.isValid()); + QVERIFY(expected.isValid()); + + const QUrl result(base.resolved(relative)); + + QVERIFY(result.isValid()); + QCOMPARE(result, expected); +} + +void tst_QUrl::resolvedWithAbsoluteSchemes_data() const +{ + QTest::addColumn<QUrl>("base"); + QTest::addColumn<QUrl>("relative"); + QTest::addColumn<QUrl>("expected"); + + QTest::newRow("Absolute file:/// against absolute FTP.") + << QUrl::fromEncoded("file:///foo/") + << QUrl::fromEncoded("ftp://example.com/") + << QUrl::fromEncoded("ftp://example.com/"); + + QTest::newRow("Absolute file:/// against absolute HTTP.") + << QUrl::fromEncoded("file:///foo/") + << QUrl::fromEncoded("http://example.com/") + << QUrl::fromEncoded("http://example.com/"); + + + QTest::newRow("Absolute file:/// against data scheme.") + << QUrl::fromEncoded("file:///foo/") + << QUrl::fromEncoded("data:application/xml,%3Ce%2F%3E") + << QUrl::fromEncoded("data:application/xml,%3Ce%2F%3E"); + + QTest::newRow("Resolve with base url and port.") + << QUrl::fromEncoded("http://www.foo.com:8080/") + << QUrl::fromEncoded("newfile.html") + << QUrl::fromEncoded("http://www.foo.com:8080/newfile.html"); +} + +void tst_QUrl::taskQTBUG_6962() +{ + //bug 6962: empty authority ignored by setAuthority + QUrl url("http://example.com/something"); + url.setAuthority(QString()); + QCOMPARE(url.authority(), QString()); +} + +void tst_QUrl::taskQTBUG_8701() +{ + //bug 8701: foo:///bar mangled to foo:/bar + QString foo_triple_bar("foo:///bar"), foo_uni_bar("foo:/bar"); + + QCOMPARE(foo_triple_bar, QUrl(foo_triple_bar).toString()); + QCOMPARE(foo_uni_bar, QUrl(foo_uni_bar).toString()); + + QCOMPARE(foo_triple_bar, QUrl(foo_triple_bar, QUrl::StrictMode).toString()); // fails + QCOMPARE(foo_uni_bar, QUrl(foo_uni_bar, QUrl::StrictMode).toString()); +} + +void tst_QUrl::effectiveTLDs_data() +{ + QTest::addColumn<QUrl>("domain"); + QTest::addColumn<QString>("TLD"); + + QTest::newRow("yes0") << QUrl::fromEncoded("http://test.co.uk") << ".co.uk"; + QTest::newRow("yes1") << QUrl::fromEncoded("http://test.com") << ".com"; + QTest::newRow("yes2") << QUrl::fromEncoded("http://www.test.de") << ".de"; + QTest::newRow("yes3") << QUrl::fromEncoded("http://test.ulm.museum") << ".ulm.museum"; + QTest::newRow("yes4") << QUrl::fromEncoded("http://www.com.krodsherad.no") << ".krodsherad.no"; + QTest::newRow("yes5") << QUrl::fromEncoded("http://www.co.uk.1.bg") << ".1.bg"; + QTest::newRow("yes6") << QUrl::fromEncoded("http://www.com.com.cn") << ".com.cn"; + QTest::newRow("yes7") << QUrl::fromEncoded("http://www.test.org.ws") << ".org.ws"; + QTest::newRow("yes9") << QUrl::fromEncoded("http://www.com.co.uk.wallonie.museum") << ".wallonie.museum"; +} + +void tst_QUrl::effectiveTLDs() +{ + QFETCH(QUrl, domain); + QFETCH(QString, TLD); + QCOMPARE(domain.topLevelDomain(), TLD); +} + +void tst_QUrl::removeAllEncodedQueryItems_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QByteArray>("key"); + QTest::addColumn<QUrl>("result"); + + QTest::newRow("test1") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&bbb=b&ccc=c") << QByteArray("bbb") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&ccc=c"); + QTest::newRow("test2") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&bbb=b&ccc=c") << QByteArray("aaa") << QUrl::fromEncoded("http://qt.nokia.com/foo?bbb=b&ccc=c"); +// QTest::newRow("test3") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&bbb=b&ccc=c") << QByteArray("ccc") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&bbb=b"); + QTest::newRow("test4") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&bbb=b&ccc=c") << QByteArray("b%62b") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&bbb=b&ccc=c"); + QTest::newRow("test5") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&b%62b=b&ccc=c") << QByteArray("b%62b") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&ccc=c"); + QTest::newRow("test6") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&b%62b=b&ccc=c") << QByteArray("bbb") << QUrl::fromEncoded("http://qt.nokia.com/foo?aaa=a&b%62b=b&ccc=c"); +} + +void tst_QUrl::removeAllEncodedQueryItems() +{ + QFETCH(QUrl, url); + QFETCH(QByteArray, key); + QFETCH(QUrl, result); + url.removeAllEncodedQueryItems(key); + QCOMPARE(url, result); +} + +QTEST_MAIN(tst_QUrl) +#include "tst_qurl.moc" |