summaryrefslogtreecommitdiffstats
path: root/tests/auto/qprocess
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qprocess')
-rw-r--r--tests/auto/qprocess/.gitignore22
-rw-r--r--tests/auto/qprocess/fileWriterProcess/fileWriterProcess.pro10
-rw-r--r--tests/auto/qprocess/fileWriterProcess/main.cpp59
-rw-r--r--tests/auto/qprocess/qprocess.pro32
-rw-r--r--tests/auto/qprocess/test/test.pro124
-rwxr-xr-xtests/auto/qprocess/testBatFiles/simple.bat2
-rwxr-xr-xtests/auto/qprocess/testBatFiles/with space.bat2
-rw-r--r--tests/auto/qprocess/testDetached/main.cpp84
-rw-r--r--tests/auto/qprocess/testDetached/testDetached.pro10
-rw-r--r--tests/auto/qprocess/testExitCodes/main.cpp48
-rw-r--r--tests/auto/qprocess/testExitCodes/testExitCodes.pro5
-rw-r--r--tests/auto/qprocess/testGuiProcess/main.cpp57
-rw-r--r--tests/auto/qprocess/testGuiProcess/testGuiProcess.pro4
-rw-r--r--tests/auto/qprocess/testProcessCrash/main.cpp53
-rw-r--r--tests/auto/qprocess/testProcessCrash/testProcessCrash.pro8
-rw-r--r--tests/auto/qprocess/testProcessDeadWhileReading/main.cpp52
-rw-r--r--tests/auto/qprocess/testProcessDeadWhileReading/testProcessDeadWhileReading.pro10
-rw-r--r--tests/auto/qprocess/testProcessEOF/main.cpp58
-rw-r--r--tests/auto/qprocess/testProcessEOF/testProcessEOF.pro9
-rw-r--r--tests/auto/qprocess/testProcessEcho/main.cpp59
-rw-r--r--tests/auto/qprocess/testProcessEcho/testProcessEcho.pro8
-rw-r--r--tests/auto/qprocess/testProcessEcho2/main.cpp58
-rw-r--r--tests/auto/qprocess/testProcessEcho2/testProcessEcho2.pro10
-rw-r--r--tests/auto/qprocess/testProcessEcho3/main.cpp61
-rw-r--r--tests/auto/qprocess/testProcessEcho3/testProcessEcho3.pro9
-rw-r--r--tests/auto/qprocess/testProcessEchoGui/main_win.cpp67
-rw-r--r--tests/auto/qprocess/testProcessEchoGui/testProcessEchoGui.pro13
-rw-r--r--tests/auto/qprocess/testProcessEnvironment/main.cpp61
-rw-r--r--tests/auto/qprocess/testProcessEnvironment/testProcessEnvironment.pro12
-rw-r--r--tests/auto/qprocess/testProcessLoopback/main.cpp57
-rw-r--r--tests/auto/qprocess/testProcessLoopback/testProcessLoopback.pro8
-rw-r--r--tests/auto/qprocess/testProcessNormal/main.cpp46
-rw-r--r--tests/auto/qprocess/testProcessNormal/testProcessNormal.pro9
-rw-r--r--tests/auto/qprocess/testProcessOutput/main.cpp66
-rw-r--r--tests/auto/qprocess/testProcessOutput/testProcessOutput.pro9
-rw-r--r--tests/auto/qprocess/testProcessSpacesArgs/main.cpp69
-rw-r--r--tests/auto/qprocess/testProcessSpacesArgs/nospace.pro9
-rw-r--r--tests/auto/qprocess/testProcessSpacesArgs/onespace.pro11
-rw-r--r--tests/auto/qprocess/testProcessSpacesArgs/twospaces.pro12
-rw-r--r--tests/auto/qprocess/testSetWorkingDirectory/main.cpp51
-rw-r--r--tests/auto/qprocess/testSetWorkingDirectory/testSetWorkingDirectory.pro7
-rw-r--r--tests/auto/qprocess/testSoftExit/main_unix.cpp62
-rw-r--r--tests/auto/qprocess/testSoftExit/main_win.cpp58
-rw-r--r--tests/auto/qprocess/testSoftExit/testSoftExit.pro16
-rw-r--r--tests/auto/qprocess/testSpaceInName/main.cpp56
-rw-r--r--tests/auto/qprocess/testSpaceInName/testSpaceInName.pro13
-rw-r--r--tests/auto/qprocess/tst_qprocess.cpp2448
47 files changed, 4014 insertions, 0 deletions
diff --git a/tests/auto/qprocess/.gitignore b/tests/auto/qprocess/.gitignore
new file mode 100644
index 0000000000..a273810042
--- /dev/null
+++ b/tests/auto/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/qprocess/fileWriterProcess/fileWriterProcess.pro b/tests/auto/qprocess/fileWriterProcess/fileWriterProcess.pro
new file mode 100644
index 0000000000..c9f87ba361
--- /dev/null
+++ b/tests/auto/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/qprocess/fileWriterProcess/main.cpp b/tests/auto/qprocess/fileWriterProcess/main.cpp
new file mode 100644
index 0000000000..06da1ecbb1
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/qprocess.pro b/tests/auto/qprocess/qprocess.pro
new file mode 100644
index 0000000000..77cfc8252e
--- /dev/null
+++ b/tests/auto/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/qprocess/test/test.pro b/tests/auto/qprocess/test/test.pro
new file mode 100644
index 0000000000..a91caddd2f
--- /dev/null
+++ b/tests/auto/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/qprocess/testBatFiles/simple.bat b/tests/auto/qprocess/testBatFiles/simple.bat
new file mode 100755
index 0000000000..900f7ae356
--- /dev/null
+++ b/tests/auto/qprocess/testBatFiles/simple.bat
@@ -0,0 +1,2 @@
+@echo off
+echo Hello \ No newline at end of file
diff --git a/tests/auto/qprocess/testBatFiles/with space.bat b/tests/auto/qprocess/testBatFiles/with space.bat
new file mode 100755
index 0000000000..900f7ae356
--- /dev/null
+++ b/tests/auto/qprocess/testBatFiles/with space.bat
@@ -0,0 +1,2 @@
+@echo off
+echo Hello \ No newline at end of file
diff --git a/tests/auto/qprocess/testDetached/main.cpp b/tests/auto/qprocess/testDetached/main.cpp
new file mode 100644
index 0000000000..c836b32e44
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testDetached/testDetached.pro b/tests/auto/qprocess/testDetached/testDetached.pro
new file mode 100644
index 0000000000..80a616b3e9
--- /dev/null
+++ b/tests/auto/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/qprocess/testExitCodes/main.cpp b/tests/auto/qprocess/testExitCodes/main.cpp
new file mode 100644
index 0000000000..58b747b9ad
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <stdlib.h>
+int main(int /* argc */, char **argv)
+{
+ return atoi(argv[1]);
+}
+
diff --git a/tests/auto/qprocess/testExitCodes/testExitCodes.pro b/tests/auto/qprocess/testExitCodes/testExitCodes.pro
new file mode 100644
index 0000000000..b08371804f
--- /dev/null
+++ b/tests/auto/qprocess/testExitCodes/testExitCodes.pro
@@ -0,0 +1,5 @@
+SOURCES += main.cpp
+CONFIG -= qt app_bundle
+CONFIG += console
+
+DESTDIR = ./
diff --git a/tests/auto/qprocess/testGuiProcess/main.cpp b/tests/auto/qprocess/testGuiProcess/main.cpp
new file mode 100644
index 0000000000..5550772dab
--- /dev/null
+++ b/tests/auto/qprocess/testGuiProcess/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtGui>
+#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;
+ fgetc(stdin); // block until fed
+
+ qDebug("Process is running");
+
+ return 0;
+}
diff --git a/tests/auto/qprocess/testGuiProcess/testGuiProcess.pro b/tests/auto/qprocess/testGuiProcess/testGuiProcess.pro
new file mode 100644
index 0000000000..15a9e8e4e4
--- /dev/null
+++ b/tests/auto/qprocess/testGuiProcess/testGuiProcess.pro
@@ -0,0 +1,4 @@
+SOURCES += main.cpp
+CONFIG += console
+DESTDIR = ./
+
diff --git a/tests/auto/qprocess/testProcessCrash/main.cpp b/tests/auto/qprocess/testProcessCrash/main.cpp
new file mode 100644
index 0000000000..65777c53d5
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+struct Foo
+{
+ int i;
+};
+
+int main()
+{
+ *(char*)0 = 0;
+ Foo *f = 0;
+ return f->i;
+}
diff --git a/tests/auto/qprocess/testProcessCrash/testProcessCrash.pro b/tests/auto/qprocess/testProcessCrash/testProcessCrash.pro
new file mode 100644
index 0000000000..abd8167313
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessDeadWhileReading/main.cpp b/tests/auto/qprocess/testProcessDeadWhileReading/main.cpp
new file mode 100644
index 0000000000..8eec89e2c4
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessDeadWhileReading/testProcessDeadWhileReading.pro b/tests/auto/qprocess/testProcessDeadWhileReading/testProcessDeadWhileReading.pro
new file mode 100644
index 0000000000..2168ba5672
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessEOF/main.cpp b/tests/auto/qprocess/testProcessEOF/main.cpp
new file mode 100644
index 0000000000..9f09664b87
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessEOF/testProcessEOF.pro b/tests/auto/qprocess/testProcessEOF/testProcessEOF.pro
new file mode 100644
index 0000000000..756bd23bb0
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessEcho/main.cpp b/tests/auto/qprocess/testProcessEcho/main.cpp
new file mode 100644
index 0000000000..f46118067b
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessEcho/testProcessEcho.pro b/tests/auto/qprocess/testProcessEcho/testProcessEcho.pro
new file mode 100644
index 0000000000..a14c1fe163
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessEcho2/main.cpp b/tests/auto/qprocess/testProcessEcho2/main.cpp
new file mode 100644
index 0000000000..b84ca7d6f1
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessEcho2/testProcessEcho2.pro b/tests/auto/qprocess/testProcessEcho2/testProcessEcho2.pro
new file mode 100644
index 0000000000..d8a303a22b
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessEcho3/main.cpp b/tests/auto/qprocess/testProcessEcho3/main.cpp
new file mode 100644
index 0000000000..f3d475d8b7
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessEcho3/testProcessEcho3.pro b/tests/auto/qprocess/testProcessEcho3/testProcessEcho3.pro
new file mode 100644
index 0000000000..3b8f2fb0d7
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessEchoGui/main_win.cpp b/tests/auto/qprocess/testProcessEchoGui/main_win.cpp
new file mode 100644
index 0000000000..dd03dcee8d
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessEchoGui/testProcessEchoGui.pro b/tests/auto/qprocess/testProcessEchoGui/testProcessEchoGui.pro
new file mode 100644
index 0000000000..b3be74cbd1
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessEnvironment/main.cpp b/tests/auto/qprocess/testProcessEnvironment/main.cpp
new file mode 100644
index 0000000000..942835751c
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessEnvironment/testProcessEnvironment.pro b/tests/auto/qprocess/testProcessEnvironment/testProcessEnvironment.pro
new file mode 100644
index 0000000000..14ddae50f3
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessLoopback/main.cpp b/tests/auto/qprocess/testProcessLoopback/main.cpp
new file mode 100644
index 0000000000..0766221ac7
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessLoopback/testProcessLoopback.pro b/tests/auto/qprocess/testProcessLoopback/testProcessLoopback.pro
new file mode 100644
index 0000000000..a14c1fe163
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessNormal/main.cpp b/tests/auto/qprocess/testProcessNormal/main.cpp
new file mode 100644
index 0000000000..5b51b89af4
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+int main()
+{
+ return 0;
+}
diff --git a/tests/auto/qprocess/testProcessNormal/testProcessNormal.pro b/tests/auto/qprocess/testProcessNormal/testProcessNormal.pro
new file mode 100644
index 0000000000..3c6a595d85
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessOutput/main.cpp b/tests/auto/qprocess/testProcessOutput/main.cpp
new file mode 100644
index 0000000000..f3fe202212
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testProcessOutput/testProcessOutput.pro b/tests/auto/qprocess/testProcessOutput/testProcessOutput.pro
new file mode 100644
index 0000000000..3b8f2fb0d7
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessSpacesArgs/main.cpp b/tests/auto/qprocess/testProcessSpacesArgs/main.cpp
new file mode 100644
index 0000000000..c6ea8cacd7
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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(argv[i]);
+ }
+#endif
+ return 0;
+}
diff --git a/tests/auto/qprocess/testProcessSpacesArgs/nospace.pro b/tests/auto/qprocess/testProcessSpacesArgs/nospace.pro
new file mode 100644
index 0000000000..f55f02e425
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessSpacesArgs/onespace.pro b/tests/auto/qprocess/testProcessSpacesArgs/onespace.pro
new file mode 100644
index 0000000000..2a56a95606
--- /dev/null
+++ b/tests/auto/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/qprocess/testProcessSpacesArgs/twospaces.pro b/tests/auto/qprocess/testProcessSpacesArgs/twospaces.pro
new file mode 100644
index 0000000000..d7c74a64c9
--- /dev/null
+++ b/tests/auto/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/qprocess/testSetWorkingDirectory/main.cpp b/tests/auto/qprocess/testSetWorkingDirectory/main.cpp
new file mode 100644
index 0000000000..135ed8ed97
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testSetWorkingDirectory/testSetWorkingDirectory.pro b/tests/auto/qprocess/testSetWorkingDirectory/testSetWorkingDirectory.pro
new file mode 100644
index 0000000000..b723604171
--- /dev/null
+++ b/tests/auto/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/qprocess/testSoftExit/main_unix.cpp b/tests/auto/qprocess/testSoftExit/main_unix.cpp
new file mode 100644
index 0000000000..4a10a15783
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testSoftExit/main_win.cpp b/tests/auto/qprocess/testSoftExit/main_win.cpp
new file mode 100644
index 0000000000..8999e70120
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testSoftExit/testSoftExit.pro b/tests/auto/qprocess/testSoftExit/testSoftExit.pro
new file mode 100644
index 0000000000..922035907a
--- /dev/null
+++ b/tests/auto/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/qprocess/testSpaceInName/main.cpp b/tests/auto/qprocess/testSpaceInName/main.cpp
new file mode 100644
index 0000000000..fd333550d4
--- /dev/null
+++ b/tests/auto/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/qprocess/testSpaceInName/testSpaceInName.pro b/tests/auto/qprocess/testSpaceInName/testSpaceInName.pro
new file mode 100644
index 0000000000..913e868d03
--- /dev/null
+++ b/tests/auto/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/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp
new file mode 100644
index 0000000000..2a8874eab3
--- /dev/null
+++ b/tests/auto/qprocess/tst_qprocess.cpp
@@ -0,0 +1,2448 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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();
+
+ // 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(5000));
+
+ 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(5);
+ 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
+
+ Q_ASSERT(processList.count() == exitStatus.count());
+ for (int i = 0; i < processList.count(); ++i) {
+ process->start(processList.at(i));
+ QVERIFY(process->waitForStarted(5000));
+ QVERIFY(process->waitForFinished(5000));
+
+ 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));
+}
+
+QTEST_MAIN(tst_QProcess)
+#include "tst_qprocess.moc"
+#endif
+