/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include QT_FORWARD_DECLARE_CLASS(Q3Process) //TESTED_CLASS= //TESTED_FILES= class tst_Q3Process : public QObject { Q_OBJECT public: tst_Q3Process(); public slots: void initTestCase(); void init(); void cleanup(); private slots: void readLineStdout_data(); void readLineStdout(); void readLineStderr_data(); void readLineStderr(); void communication_data(); void communication(); void canReadLineStdout_data(); void canReadLineStdout(); void canReadLineStderr_data(); void canReadLineStderr(); void startWithNoEnvironment(); void startWithEmptyStringArgument(); protected slots: void processExited(); void exitLoopSlot(); private: Q3Process *proc; QStringList linesReadStdout; QStringList linesReadStderr; }; tst_Q3Process::tst_Q3Process() : proc(0) { } void tst_Q3Process::initTestCase() { #ifdef Q_OS_WIN // cd up to be able to locate the binary of the sub-process. QDir workingDirectory = QDir::current(); if (workingDirectory.absolutePath().endsWith(QLatin1String("/debug"), Qt::CaseInsensitive) || workingDirectory.absolutePath().endsWith(QLatin1String("/release"), Qt::CaseInsensitive)) { QVERIFY(workingDirectory.cdUp()); QVERIFY(QDir::setCurrent(workingDirectory.absolutePath())); } #endif } void tst_Q3Process::init() { linesReadStdout.clear(); linesReadStderr.clear(); } void tst_Q3Process::cleanup() { if ( proc ) { proc->kill(); delete proc; proc = 0; } } void tst_Q3Process::readLineStdout_data() { QTest::addColumn("input"); QTest::addColumn("res"); QStringList l; QTest::newRow( "unix_0" ) << QString("a\nbc\ndef\nghij\n") << (QStringList)( l << "a" << "bc" << "def" << "ghij" ); l.clear(); QTest::newRow( "unix_1" ) << QString("a\nbc\ndef\nghij") << (QStringList)( l << "a" << "bc" << "def" << "ghij" ); l.clear(); QTest::newRow( "unix_2" ) << QString("a\nbc\n\ndef\nghij\n") << (QStringList)( l << "a" << "bc" << "" << "def" << "ghij" ); l.clear(); QTest::newRow( "windows_0" ) << QString("a\r\nbc\r\ndef\r\nghij\r\n") << (QStringList)( l << "a" << "bc" << "def" << "ghij" ); l.clear(); QTest::newRow( "windows_1" ) << QString("a\r\nbc\r\ndef\r\nghij") << (QStringList)( l << "a" << "bc" << "def" << "ghij" ); l.clear(); QTest::newRow( "windows_2" ) << QString("a\r\nbc\r\n\r\ndef\r\nghij\r\n") << (QStringList)( l << "a" << "bc" << "" << "def" << "ghij" ); l.clear(); QTest::newRow( "mixed_0" ) << QString("a\r\nbc\ndef\r\nghij\n") << (QStringList)( l << "a" << "bc" << "def" << "ghij" ); l.clear(); QTest::newRow( "mixed_1" ) << QString("a\nbc\r\ndef\nghij\r\n") << (QStringList)( l << "a" << "bc" << "def" << "ghij" ); l.clear(); QTest::newRow( "mixed_2" ) << QString("a\nbc\r\r\ndef\r\r\r\nghij\r\r\r\r\n") << (QStringList)( l << "a" << "bc\r" << "def\r\r" << "ghij\r\r\r" ); l.clear(); } void tst_Q3Process::readLineStdout() { QFETCH( QString, input ); if (proc) delete proc; proc = new Q3Process( QString("cat/cat") ); connect( proc, SIGNAL(processExited()), SLOT(processExited()) ); QVERIFY( proc->launch( input ) ); QTestEventLoop::instance().enterLoop( 29 ); if ( QTestEventLoop::instance().timeout() ) QFAIL( "Operation timed out" ); QTEST( linesReadStdout, "res" ); } void tst_Q3Process::readLineStderr_data() { readLineStdout_data(); } void tst_Q3Process::readLineStderr() { QFETCH( QString, input ); if (proc) delete proc; proc = new Q3Process( QString("cat/cat -stderr").split(' ') ); connect( proc, SIGNAL(processExited()), SLOT(processExited()) ); QVERIFY( proc->launch( input ) ); QTestEventLoop::instance().enterLoop( 29 ); if ( QTestEventLoop::instance().timeout() ) QFAIL( "Operation timed out" ); QTEST( linesReadStderr, "res" ); } void tst_Q3Process::communication_data() { QTest::addColumn("command"); QTest::addColumn("commFlags"); QTest::addColumn("input"); QTest::addColumn("resStdout"); QTest::addColumn("resStderr"); QTest::newRow( "no_dup_0" ) << QString("cat/cat").split(' ') << ( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr ) << QString("12345") << QString("12345") << QString(); QTest::newRow( "no_dup_1" ) << QString("cat/cat -stderr").split(' ') << ( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr ) << QString("12345") << QString() << QString("12345"); QTest::newRow( "no_dup_2" ) << QString("cat/cat -stdout_and_stderr").split(' ') << ( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr ) << QString("12345") << QString("12345") << QString("23456"); QTest::newRow( "dup_0" ) << QString("cat/cat").split(' ') << ( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr | Q3Process::DupStderr ) << QString("12345") << QString("12345") << QString(); QTest::newRow( "dup_1" ) << QString("cat/cat -stderr").split(' ') << ( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr | Q3Process::DupStderr ) << QString("12345") << QString("12345") << QString(); QTest::newRow( "dup_2" ) << QString("cat/cat -stdout_and_stderr").split(' ') << ( Q3Process::Stdin | Q3Process::Stdout | Q3Process::Stderr | Q3Process::DupStderr ) << QString("12345") << QString("1223344556") << QString(); } void tst_Q3Process::communication() { for ( int i=0; i<2; i++ ) { cleanup(); QFETCH( QStringList, command ); QFETCH( int, commFlags ); QFETCH( QString, input ); if (proc) delete proc; proc = new Q3Process( command ); proc->setCommunication( commFlags ); connect( proc, SIGNAL(processExited()), SLOT(processExited()) ); QVERIFY( proc->launch( input ) ); QTestEventLoop::instance().enterLoop( 29 ); if ( QTestEventLoop::instance().timeout() ) QFAIL( "Operation timed out" ); if ( i == 0 ) { QTEST( QString( proc->readStdout() ), "resStdout" ); QTEST( QString( proc->readStderr() ), "resStderr" ); } else { QTEST( QString( proc->readStdout() ), "resStdout" ); QTEST( QString( proc->readStderr() ), "resStderr" ); } } } void tst_Q3Process::canReadLineStdout_data() { readLineStdout_data(); } void tst_Q3Process::canReadLineStdout() { // This function tests the busy-loop abilities of the canReadLineStdout() // function. QFETCH( QString, input ); QFETCH(QStringList, res); if (proc) delete proc; proc = new Q3Process( QString("cat/cat") ); QVERIFY( proc->start() ); proc->writeToStdin( input ); proc->flushStdin(); proc->closeStdin(); do { connect(proc, SIGNAL(readyReadStdout()), this, SLOT(exitLoopSlot())); QTestEventLoop::instance().enterLoop(5); if (QTestEventLoop::instance().timeout()) { if (!proc->isRunning()) break; QFAIL("Timed out while waiting for my kids"); } // q3process can (actually!) emit readyRead() when // canReadLineStdout() is called. proc->disconnect(); while ( proc->canReadLineStdout() ) linesReadStdout << proc->readLineStdout(); } while (linesReadStdout.size() < res.size() && proc->isRunning()); // q3process can (actually!) emit readyRead() when // canReadLineStdout() is called. proc->disconnect(); // if the last line is not terminated with a newline, we get it only after // we determined that the process is not running anymore if ( proc->canReadLineStdout() ) linesReadStdout << proc->readLineStdout(); QCOMPARE( linesReadStdout, res ); } void tst_Q3Process::exitLoopSlot() { QTestEventLoop::instance().exitLoop(); } void tst_Q3Process::canReadLineStderr_data() { readLineStdout_data(); } void tst_Q3Process::canReadLineStderr() { // This function tests the busy-loop abilities of the canReadLineStderr() // function. QFETCH( QString, input ); QFETCH(QStringList, res); if (proc) delete proc; proc = new Q3Process( QString("cat/cat -stderr").split(' ') ); QVERIFY( proc->start() ); proc->writeToStdin( input ); proc->flushStdin(); proc->closeStdin(); do { connect(proc, SIGNAL(readyReadStderr()), this, SLOT(exitLoopSlot())); QTestEventLoop::instance().enterLoop(5); if (QTestEventLoop::instance().timeout()) { if (!proc->isRunning()) break; QFAIL("Timed out while waiting for my kids"); } // q3process can (actually!) emit readyRead() when // canReadLineStdout() is called. proc->disconnect(); while ( proc->canReadLineStderr() ) linesReadStderr << proc->readLineStderr(); } while (linesReadStderr.size() < res.size() && proc->isRunning()); // q3process can (actually!) emit readyRead() when // canReadLineStdout() is called. proc->disconnect(); // if the last line is not terminated with a newline, we get it only after // we determined that the process is not running anymore if ( proc->canReadLineStderr() ) linesReadStderr << proc->readLineStderr(); QCOMPARE( linesReadStderr, res ); } void tst_Q3Process::processExited() { if ( QTest::currentTestFunction() == QLatin1String("readLineStdout") ) { QVERIFY( proc != 0 ); // q3process can (actually!) emit readyRead() when // canReadLineStdout() is called. proc->disconnect(); while ( proc->canReadLineStdout() ) linesReadStdout << proc->readLineStdout(); // if canReadLine...() returns FALSE, the readLine...() function should // return QString::null QVERIFY( proc->readLineStdout().isNull() ); QTestEventLoop::instance().exitLoop(); } else if ( QTest::currentTestFunction() == QLatin1String("readLineStderr") ) { QVERIFY( proc != 0 ); // q3process can (actually!) emit readyRead() when // canReadLineStdout() is called. proc->disconnect(); while ( proc->canReadLineStderr() ) linesReadStderr << proc->readLineStderr(); // if canReadLine...() returns FALSE, the readLine...() function should // return QString::null QVERIFY( proc->readLineStderr().isNull() ); QTestEventLoop::instance().exitLoop(); } else if ( QTest::currentTestFunction() == QLatin1String("communication") ) { QTestEventLoop::instance().exitLoop(); } } void tst_Q3Process::startWithNoEnvironment() { QStringList args; QByteArray result; #ifdef Q_OS_MACX args << "./echo/echo.app"; result = "./echo/echo.app/Contents/MacOS/echo"; #elif defined Q_OS_WIN args << "./echo/echo"; result = "echo"; #else args << "./echo/echo"; result = args[0]; #endif args << "foo"; proc = new Q3Process(args); QVERIFY(proc->start(/* environment = */ 0)); connect(proc, SIGNAL(readyReadStdout()), this, SLOT(exitLoopSlot())); QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); #ifdef Q_OS_WIN // on different windows compilers the first arg is different, // some just pass what was passed to createprocess while others // expand the entire path. QVERIFY(proc->readStdout().contains(result)); #else QCOMPARE(proc->readStdout(), result); #endif } void tst_Q3Process::startWithEmptyStringArgument() { // Test that this doesn't assert (task 122353) Q3Process process("cmd"); process.addArgument(QString()); QStringList env; process.start(&env); } QTEST_MAIN(tst_Q3Process) #include "tst_q3process.moc"