diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /tools/qtestlib | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'tools/qtestlib')
-rw-r--r-- | tools/qtestlib/qtestlib.pro | 4 | ||||
-rw-r--r-- | tools/qtestlib/updater/main.cpp | 178 | ||||
-rw-r--r-- | tools/qtestlib/updater/updater.pro | 10 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/activesyncconnection.cpp | 485 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/activesyncconnection.h | 86 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/bootstrapped.pri | 38 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/cetest.pro | 47 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/deployment.cpp | 267 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/deployment.h | 75 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/main.cpp | 351 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/qmake_include.pri | 7 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/remoteconnection.cpp | 68 | ||||
-rw-r--r-- | tools/qtestlib/wince/cetest/remoteconnection.h | 82 | ||||
-rw-r--r-- | tools/qtestlib/wince/remotelib/commands.cpp | 120 | ||||
-rw-r--r-- | tools/qtestlib/wince/remotelib/commands.h | 51 | ||||
-rw-r--r-- | tools/qtestlib/wince/remotelib/remotelib.pro | 15 | ||||
-rw-r--r-- | tools/qtestlib/wince/wince.pro | 2 |
17 files changed, 1886 insertions, 0 deletions
diff --git a/tools/qtestlib/qtestlib.pro b/tools/qtestlib/qtestlib.pro new file mode 100644 index 0000000..da94e81 --- /dev/null +++ b/tools/qtestlib/qtestlib.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +!wince*: SUBDIRS += updater +wince*: contains(QT_CONFIG, cetest): SUBDIRS += wince +CONFIG += ordered diff --git a/tools/qtestlib/updater/main.cpp b/tools/qtestlib/updater/main.cpp new file mode 100644 index 0000000..38628cf --- /dev/null +++ b/tools/qtestlib/updater/main.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtCore> + +#include <stdio.h> + +QT_USE_NAMESPACE + +static void printHelp(char *argv[]) +{ + qDebug("Usage: %s [-diff] FILES", argv[0] ? argv[0] : "qtest2to4"); + qDebug("updates files from QtTestLib 2.x to QTestLib 4.1"); + qDebug("\noptions:\n -diff Don't write any changes, output differences instead."); + exit(2); +} + +int main(int argc, char *argv[]) +{ + bool printDiff = false; + int i = 1; + + if (argc == 1) + printHelp(argv); + if (argv[1][0] == '-') { + if (qstrcmp(argv[1], "-diff") == 0) { + printDiff = true; + ++i; + } else { + qDebug("Unknown option: %s\n", argv[1]); + printHelp(argv); + } + } + + QRegExp dataHeaderRx(QLatin1String("_data(\\s*)\\((\\s*)QtTestTable\\s*\\&\\s*\\w*\\s*\\)")); + QRegExp defElemRx(QLatin1String("\\w+\\.defineElement\\s*\\(\\s*\"(.+)\"\\s*,\\s*\"(.+)\"\\s*\\)")); + defElemRx.setMinimal(true); + QRegExp addDataRx(QLatin1String("\\*\\w+\\.newData(\\s*)(\\(\\s*\".*\"\\s*\\))")); + addDataRx.setMinimal(true); + QRegExp nsRx(QLatin1String("namespace(\\s+)QtTest")); + QRegExp callRx(QLatin1String("QtTest(\\s*)::")); + + enum { MacroCount = 11 }; + static const char *macroNames[MacroCount] = { + "VERIFY", "FAIL", "VERIFY2", "COMPARE", "SKIP", "VERIFY_EVENT", + "EXPECT_FAIL", "FETCH", "FETCH_GLOBAL", "TEST", "WARN" + }; + + for (; i < argc; ++i) { + QFile f(QString::fromLocal8Bit(argv[i])); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) + qFatal("Unable to open file '%s' for reading: %s", argv[i], qPrintable(f.errorString())); + + if (printDiff) + printf("diff %s\n", argv[i]); + + QStringList contents; + int lineNumber = 0; + int changedLines = 0; + while (!f.atEnd()) { + QString origLine = QString::fromLatin1(f.readLine()); + QString line = origLine; + ++lineNumber; + + if (dataHeaderRx.indexIn(line) != -1) { + QString ws = dataHeaderRx.cap(1); + line.replace(dataHeaderRx, QString::fromLatin1("_data%1()").arg(ws)); + } + if (defElemRx.indexIn(line) != -1) { + QString type = defElemRx.cap(1); + QString name = defElemRx.cap(2); + if (type.endsWith(QLatin1Char('>'))) + type.append(QLatin1Char(' ')); + line.replace(defElemRx, QString::fromLatin1("QTest::addColumn<%1>(\"%2\")").arg( + type).arg(name)); + } + if (addDataRx.indexIn(line) != -1) { + QString repl = QLatin1String("QTest::newRow"); + repl += addDataRx.cap(1); + repl += addDataRx.cap(2); + line.replace(addDataRx, repl); + } + if (nsRx.indexIn(line) != -1) + line.replace(nsRx, QString::fromLatin1("namespace%1QTest").arg(nsRx.cap(1))); + int pos = 0; + while ((pos = callRx.indexIn(line, pos)) != -1) { + line.replace(callRx, QString::fromLatin1("QTest%1::").arg(callRx.cap(1))); + pos += callRx.matchedLength(); + } + + line.replace(QLatin1String("QTTEST_MAIN"), QLatin1String("QTEST_MAIN")); + line.replace(QLatin1String("QTTEST_APPLESS_MAIN"), QLatin1String("QTEST_APPLESS_MAIN")); + line.replace(QLatin1String("QTTEST_NOOP_MAIN"), QLatin1String("QTEST_NOOP_MAIN")); + line.replace(QLatin1String("QtTestEventLoop"), QLatin1String("QTestEventLoop")); + line.replace(QLatin1String("QtTestEventList"), QLatin1String("QTestEventList")); + line.replace(QLatin1String("QtTestAccessibility"), QLatin1String("QTestAccessibility")); + line.replace(QLatin1String("QTest::sleep"), QLatin1String("QTest::qSleep")); + line.replace(QLatin1String("QTest::wait"), QLatin1String("QTest::qWait")); + + for (int m = 0; m < MacroCount; ++m) { + QRegExp macroRe(QString::fromLatin1("\\b%1(\\s*\\()").arg( + QLatin1String(macroNames[m]))); + QString newMacroName = QLatin1Char('Q') + QString::fromLatin1(macroNames[m]); + int pos = 0; + while ((pos = macroRe.indexIn(line)) != -1) { + line.replace(macroRe, newMacroName + macroRe.cap(1)); + pos += macroRe.matchedLength(); + } + } + + if (line != origLine) { + if (printDiff) { + printf("%dc%d\n", lineNumber, lineNumber); + printf("<%s", qPrintable(origLine)); + printf("---\n"); + printf(">%s", qPrintable(line)); + } + ++changedLines; + } + + contents.append(line); + } + f.close(); + + if (printDiff) + continue; + qDebug("%s: %d change%s made.", argv[i], changedLines, changedLines == 1 ? "" : "s"); + if (!changedLines) + continue; + + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) + qFatal("Unable to open file '%s' for writing: %s", argv[i], qPrintable(f.errorString())); + foreach (QString s, contents) + f.write(s.toLatin1()); + f.close(); + } + + return 0; +} + diff --git a/tools/qtestlib/updater/updater.pro b/tools/qtestlib/updater/updater.pro new file mode 100644 index 0000000..42e1b74 --- /dev/null +++ b/tools/qtestlib/updater/updater.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET += +DEPENDPATH += . +INCLUDEPATH += . + +SOURCES += main.cpp + +QT = core + +DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII diff --git a/tools/qtestlib/wince/cetest/activesyncconnection.cpp b/tools/qtestlib/wince/cetest/activesyncconnection.cpp new file mode 100644 index 0000000..fc0e7b4 --- /dev/null +++ b/tools/qtestlib/wince/cetest/activesyncconnection.cpp @@ -0,0 +1,485 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "activesyncconnection.h" +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo> +#include <rapi.h> + +extern void debugOutput(const QString& text, int level); + +ActiveSyncConnection::ActiveSyncConnection() + : AbstractRemoteConnection() + , connected(false) +{ +} + +ActiveSyncConnection::~ActiveSyncConnection() +{ + if (isConnected()) + disconnect(); +} + +bool ActiveSyncConnection::connect(QVariantList&) +{ + if (connected) + return true; + connected = false; + RAPIINIT init; + init.cbSize = sizeof(init); + if (CeRapiInitEx(&init) != S_OK) + return connected; + + DWORD res; + res = WaitForMultipleObjects(1,&(init.heRapiInit),true, 5000); + if ((res == -1) || (res == WAIT_TIMEOUT) || (init.hrRapiInit != S_OK)) + return connected; + + connected = true; + return connected; +} + +void ActiveSyncConnection::disconnect() +{ + connected = false; + CeRapiUninit(); +} + +bool ActiveSyncConnection::isConnected() const +{ + return connected; +} + +bool ActiveSyncConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists) +{ + if (failIfExists) { + CE_FIND_DATA search; + HANDLE searchHandle = CeFindFirstFile(deviceDest.utf16(), &search); + if (searchHandle != INVALID_HANDLE_VALUE) { + CeFindClose(searchHandle); + return false; + } + } + + QFile file(localSource); + if (!file.exists()) + return false; + if (!file.open(QIODevice::ReadOnly)) { + debugOutput(QString::fromLatin1(" Could not open source file"),2); + if (file.size() == 0) { + // Create an empy file + deleteFile(deviceDest); + HANDLE deviceHandle = CeCreateFile(deviceDest.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (deviceHandle != INVALID_HANDLE_VALUE) { + CeCloseHandle(deviceHandle); + return true; + } + } + return false; + } + + deleteFile(deviceDest); + HANDLE deviceHandle = CeCreateFile(deviceDest.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (deviceHandle == INVALID_HANDLE_VALUE) { + debugOutput(QString::fromLatin1(" Could not create target file"), 2); + return false; + } + + DWORD written = 0; + int currentPos = 0; + int size = file.size(); + DWORD toWrite = 0; + const int bufferSize = 65000; + QByteArray data; + data.reserve(bufferSize); + while (currentPos < size) { + data = file.read(bufferSize); + if (data.size() <= 0) { + wprintf( L"Error while reading file!\n"); + return false; + } + if (size - currentPos > bufferSize ) + toWrite = bufferSize; + else + toWrite = size - currentPos; + if (toWrite == 0) + break; + if (!CeWriteFile(deviceHandle, data.data() , toWrite, &written, NULL)) { + debugOutput(QString::fromLatin1(" Could not write File"), 2); + return false; + } + currentPos += written; + data.clear(); + wprintf( L"%s -> %s (%d / %d) %d %%\r", localSource.utf16() , deviceDest.utf16(), currentPos , size, (100*currentPos)/size ); + } + wprintf(L"\n"); + + // Copy FileTime for update verification + FILETIME creationTime, accessTime, writeTime; + HANDLE localHandle = CreateFile(localSource.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (localHandle != INVALID_HANDLE_VALUE) { + if (GetFileTime(localHandle, &creationTime, &accessTime, &writeTime)) { + LocalFileTimeToFileTime(&writeTime, &writeTime); + if (!CeSetFileTime(deviceHandle, &writeTime, NULL, NULL)) { + debugOutput(QString::fromLatin1(" Could not write time values"), 0); + } + } + CloseHandle(localHandle); + } + CeCloseHandle(deviceHandle); + + DWORD attributes = GetFileAttributes(localSource.utf16()); + if (attributes != -1 ) + CeSetFileAttributes(deviceDest.utf16(), attributes); + return true; +} + +bool ActiveSyncConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive) +{ + QDir dir(localSource); + if (!dir.exists()) + return false; + + deleteDirectory(deviceDest, recursive); + CeCreateDirectory(deviceDest.utf16(), NULL); + foreach(QString entry, dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot)) { + QString source = localSource + "\\" + entry; + QString target = deviceDest + "\\" + entry; + QFileInfo info(source); + if (info.isDir()) { + if (recursive) { + if (!copyDirectoryToDevice(source, target, recursive)) + return false; + } + } else { + if (!copyFileToDevice(source, target)) + return false; + } + } + return true; +} + +bool ActiveSyncConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists) +{ + QFile target(localDest); + if (failIfExists && target.exists()) { + debugOutput(QString::fromLatin1(" Not allowed to overwrite file"), 2); + return false; + } + + if (target.exists()) + target.remove(); + + HANDLE deviceHandle = CeCreateFile(deviceSource.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (deviceHandle == INVALID_HANDLE_VALUE) { + debugOutput(QString::fromLatin1(" Could not open file on device"), 2); + return false; + } + + DWORD fileSize = CeGetFileSize( deviceHandle, NULL ); + if (fileSize == -1) { + debugOutput(QString::fromLatin1(" Could not stat filesize of remote file"), 2); + CeCloseHandle(deviceHandle); + return false; + } + + if (!target.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + debugOutput(QString::fromLatin1(" Could not open local file for writing"), 2); + CeCloseHandle(deviceHandle); + return false; + } + + int bufferSize = 65000; + char *buffer = (char*) malloc(bufferSize); + DWORD bufferRead = 0; + DWORD bufferWritten = 0; + bool readUntilEnd = false; + while(CeReadFile(deviceHandle, buffer, bufferSize, &bufferRead, NULL)) { + if (bufferRead == 0) { + readUntilEnd = true; + break; + } + target.write(buffer, bufferRead); + bufferWritten += bufferRead; + wprintf(L"%s -> %s (%d / %d) %d %%\r", deviceSource.utf16(), localDest.utf16(), bufferWritten, fileSize, (100*bufferWritten)/fileSize); + } + wprintf(L"\n"); + + if (!readUntilEnd) { + debugOutput(QString::fromLatin1(" an error occured during copy"), 2); + return false; + } + + CeCloseHandle(deviceHandle); + return true; +} + +bool ActiveSyncConnection::copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive) +{ + if (!QDir(localDest).exists() && !QDir(localDest).mkpath(QDir(localDest).absolutePath())) { + debugOutput(QString::fromLatin1(" Could not create local path"), 2); + } + + QString searchArg = deviceSource + "\\*"; + CE_FIND_DATA data; + HANDLE searchHandle = CeFindFirstFile(searchArg.utf16(), &data); + if (searchHandle == INVALID_HANDLE_VALUE) { + // We return true because we might be in a recursive call + // where nothing is to copy and the copy process + // might still be correct + return true; + } + + do { + QString srcFile = deviceSource + "\\" + QString::fromUtf16(data.cFileName); + QString destFile = localDest + "\\" + QString::fromUtf16(data.cFileName); + if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (recursive && !copyDirectoryFromDevice(srcFile, destFile, recursive)) { + wprintf(L"Copy of subdirectory(%s) failed\n", srcFile.utf16()); + return false; + } + } else { + copyFileFromDevice(srcFile, destFile, false); + } + } while(CeFindNextFile(searchHandle, &data)); + CeFindClose(searchHandle); + return true; +} + +bool ActiveSyncConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists) +{ + return CeCopyFile(QDir::toNativeSeparators(srcFile).utf16(), + QDir::toNativeSeparators(destFile).utf16(), failIfExists); +} + +bool ActiveSyncConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory, + bool recursive) +{ + CeCreateDirectory(destDirectory.utf16(), NULL); + QString searchArg = srcDirectory + "\\*"; + CE_FIND_DATA data; + HANDLE searchHandle = CeFindFirstFile(searchArg.utf16(), &data); + if (searchHandle == INVALID_HANDLE_VALUE) { + // We return true because we might be in a recursive call + // where nothing is to copy and the copy process + // might still be correct + return true; + } + + do { + QString srcFile = srcDirectory + "\\" + QString::fromUtf16(data.cFileName); + QString destFile = destDirectory + "\\" + QString::fromUtf16(data.cFileName); + if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (recursive && !copyDirectory(srcFile, destFile, recursive)) { + wprintf(L"Copy of subdirectory(%s) failed\n", srcFile.utf16()); + return false; + } + } else { + debugOutput(QString::fromLatin1("Copy %1 -> %2\n").arg(srcFile).arg(destFile), 0); + CeCopyFile(srcFile.utf16(), destFile.utf16(), false); + } + } while(CeFindNextFile(searchHandle, &data)); + CeFindClose(searchHandle); + return true; +} + +bool ActiveSyncConnection::deleteFile(const QString &fileName) +{ + CeSetFileAttributes(fileName.utf16(), FILE_ATTRIBUTE_NORMAL); + return CeDeleteFile(fileName.utf16()); +} + +bool ActiveSyncConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists) +{ + HANDLE hFind; + CE_FIND_DATA FindFileData; + QString FileName = directory + "\\*"; + hFind = CeFindFirstFile(FileName.utf16(), &FindFileData); + if( hFind == INVALID_HANDLE_VALUE ) + return CeRemoveDirectory(directory.utf16()); + + if (failIfContentExists) + return false; + + do { + QString FileName = directory + "\\" + QString::fromUtf16(FindFileData.cFileName); + if((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (recursive) + if (!deleteDirectory(FileName, recursive, failIfContentExists)) + return false; + } else { + if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + CeSetFileAttributes(FileName.utf16(), FILE_ATTRIBUTE_NORMAL); + if( !CeDeleteFile(FileName.utf16()) ) + break; + } + } while(CeFindNextFile(hFind,&FindFileData)); + CeFindClose(hFind); + + return CeRemoveDirectory(directory.utf16()); +} + +bool ActiveSyncConnection::execute(QString program, QString arguments, int timeout, int *returnValue) +{ + if (!isConnected()) { + qWarning("Cannot execute, connect to device first!"); + return false; + } + + PROCESS_INFORMATION* pid = new PROCESS_INFORMATION; + bool result = false; + if (timeout != 0) { + // If we want to wait, we have to use CeRapiInvoke, as CeCreateProcess has no way to wait + // until the process ends. The lib must have been build and also deployed already. + if (!isConnected() && !connect()) + return false; + + QString dllLocation = "\\Windows\\QtRemote.dll"; + QString functionName = "qRemoteLaunch"; + + DWORD outputSize; + BYTE* output; + IRAPIStream *stream; + int returned = 0; + HRESULT res = CeRapiInvoke(dllLocation.utf16(), functionName.utf16(), 0, 0, &outputSize, &output, &stream, 0); + if (S_OK != res) { + if (S_OK != CeGetLastError()) + debugOutput(QString::fromLatin1("Error: Could not invoke method on QtRemote"),1); + else + debugOutput(QString::fromLatin1("Error: QtRemote return unexpectedly with error Code %1").arg(res), 1); + } else { + DWORD written; + int strSize = program.length(); + if (S_OK != stream->Write(&strSize, sizeof(strSize), &written)) { + qWarning(" Could not write appSize to process"); + return false; + } + if (S_OK != stream->Write(program.utf16(), program.length()*sizeof(wchar_t), &written)) { + qWarning(" Could not write appName to process"); + return false; + } + strSize = arguments.length(); + if (S_OK != stream->Write(&strSize, sizeof(strSize), &written)) { + qWarning(" Could not write argumentSize to process"); + return false; + } + if (S_OK != stream->Write(arguments.utf16(), arguments.length()*sizeof(wchar_t), &written)) { + qWarning(" Could not write arguments to process"); + return false; + } + if (S_OK != stream->Write(&timeout, sizeof(timeout), &written)) { + qWarning(" Could not write waiting option to process"); + return false; + } + + if (S_OK != stream->Read(&returned, sizeof(returned), &written)) { + qWarning(" Could not access return value of process"); + } + result = true; + } + + + if (returnValue) + *returnValue = returned; + } else { + // We do not need to invoke another lib etc, if we are not interested in results anyway... + result = CeCreateProcess(program.utf16(), arguments.utf16(), 0, 0, false, 0, 0, 0, 0, pid); + } + return result; +} + +bool ActiveSyncConnection::createDirectory(const QString &path, bool deleteBefore) +{ + if (deleteBefore) + deleteDirectory(path); + QStringList separated = path.split(QLatin1Char('\\')); + QString current = QLatin1String("\\"); + bool result; + for (int i=1; i < separated.size(); ++i) { + current += separated.at(i); + result = CeCreateDirectory(current.utf16(), NULL); + current += QLatin1String("\\"); + } + return result; +} + +bool ActiveSyncConnection::timeStampForLocalFileTime(FILETIME* fTime) const +{ + QString tmpFile = QString::fromLatin1("\\qt_tmp_ftime_convert"); + HANDLE remoteHandle = CeCreateFile(tmpFile.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (remoteHandle == INVALID_HANDLE_VALUE) + return false; + + LocalFileTimeToFileTime(fTime, fTime); + + if (!CeSetFileTime(remoteHandle, fTime, NULL, NULL)) { + CeCloseHandle(remoteHandle); + return false; + } + + CeCloseHandle(remoteHandle); + remoteHandle = CeCreateFile(tmpFile.utf16(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (remoteHandle == INVALID_HANDLE_VALUE) + return false; + if (!CeGetFileTime(remoteHandle, fTime, NULL, NULL)) { + CeCloseHandle(remoteHandle); + return false; + } + + CeCloseHandle(remoteHandle); + CeDeleteFile(tmpFile.utf16()); + return true; +} + +bool ActiveSyncConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const +{ + HANDLE deviceHandle = CeCreateFile(fileName.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (deviceHandle == INVALID_HANDLE_VALUE) + return false; + + bool result = true; + if (!CeGetFileTime(deviceHandle, deviceCreationTime, NULL, NULL)) + result = false; + + CeCloseHandle(deviceHandle); + return result; +} diff --git a/tools/qtestlib/wince/cetest/activesyncconnection.h b/tools/qtestlib/wince/cetest/activesyncconnection.h new file mode 100644 index 0000000..44ff356 --- /dev/null +++ b/tools/qtestlib/wince/cetest/activesyncconnection.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ACTIVESYNC_REMOTECONNECTION_H +#define ACTIVESYNC_REMOTECONNECTION_H + +#include "remoteconnection.h" + +#if defined(Q_OS_WIN32) +#define REMOTELIBNAME "remotecommands" +#endif + +class ActiveSyncConnection : public AbstractRemoteConnection +{ +public: + ActiveSyncConnection(); + virtual ~ActiveSyncConnection(); + + bool connect(QVariantList &list = QVariantList()); + void disconnect(); + bool isConnected() const; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false); + bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true); + bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false); + bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true); + + bool timeStampForLocalFileTime(FILETIME*) const; + bool fileCreationTime(const QString &fileName, FILETIME*) const; + + // These functions only work on files existing on the device + bool copyFile(const QString&, const QString&, bool failIfExists = false); + bool copyDirectory(const QString&, const QString&, bool recursive = true); + bool deleteFile(const QString&); + bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false); + bool moveFile(const QString&, const QString&, bool FailIfExists = false); + bool moveDirectory(const QString&, const QString&, bool recursive = true); + + bool createDirectory(const QString&, bool deleteBefore=false); + + bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL); +private: + bool connected; +}; + +#endif diff --git a/tools/qtestlib/wince/cetest/bootstrapped.pri b/tools/qtestlib/wince/cetest/bootstrapped.pri new file mode 100644 index 0000000..39f24c2 --- /dev/null +++ b/tools/qtestlib/wince/cetest/bootstrapped.pri @@ -0,0 +1,38 @@ +# Bootstrapped Input +SOURCES += \ + $$QT_SOURCE_TREE/src/corelib/tools/qstring.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qstringlist.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfile.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qdir.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qabstractfileengine.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_win.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator_win.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qfileinfo.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qtemporaryfile.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qdiriterator.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qiodevice.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qbuffer.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qtextstream.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qurl.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qsettings.cpp \ + $$QT_SOURCE_TREE/src/corelib/io/qsettings_win.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qdatetime.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qlocale.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qbytearray.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qbytearraymatcher.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qvector.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qvsnprintf.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qlistdata.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qhash.cpp \ + $$QT_SOURCE_TREE/src/corelib/global/qglobal.cpp \ + $$QT_BUILD_TREE/src/corelib/global/qconfig.cpp \ + $$QT_SOURCE_TREE/src/corelib/global/qmalloc.cpp \ + $$QT_SOURCE_TREE/src/corelib/global/qnumeric.cpp \ + $$QT_SOURCE_TREE/src/corelib/global/qlibraryinfo.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qregexp.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qmap.cpp \ + $$QT_SOURCE_TREE/src/corelib/tools/qbitarray.cpp \ + $$QT_SOURCE_TREE/src/corelib/kernel/qmetatype.cpp \ + $$QT_SOURCE_TREE/src/corelib/kernel/qvariant.cpp diff --git a/tools/qtestlib/wince/cetest/cetest.pro b/tools/qtestlib/wince/cetest/cetest.pro new file mode 100644 index 0000000..d66fa33 --- /dev/null +++ b/tools/qtestlib/wince/cetest/cetest.pro @@ -0,0 +1,47 @@ +TEMPLATE = app +TARGET = cetest +DESTDIR = ../../../../bin +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +CONFIG += console no_batch +CONFIG -= qt + +DEFINES += QT_BUILD_QMAKE QT_BOOTSTRAPPED QT_NO_CODECS QT_LITE_UNICODE QT_NO_LIBRARY \ + QT_NO_STL QT_NO_COMPRESS QT_NO_DATASTREAM \ + QT_NO_TEXTCODEC QT_NO_UNICODETABLES QT_NO_THREAD \ + QT_NO_SYSTEMLOCALE QT_NO_GEOM_VARIANT \ + QT_NODLL QT_NO_QOBJECT + +INCLUDEPATH = \ + $$QT_SOURCE_TREE/tools/qtestlib/ce/cetest \ + $$QT_SOURCE_TREE/qmake \ + $$QT_BUILD_TREE/include \ + $$QT_BUILD_TREE/include/QtCore \ + $$QT_BUILD_TREE/include/QtScript \ + $$QT_BUILD_TREE/src/corelib/global + +DEPENDPATH += $$QT_BUILD_TREE/src/corelib/tools $$QT_BUILD_TREE/src/corelib/io + +# Input +HEADERS += \ + remoteconnection.h \ + activesyncconnection.h \ + deployment.h + +SOURCES += \ + remoteconnection.cpp \ + activesyncconnection.cpp \ + deployment.cpp \ + main.cpp + +win32-msvc*:LIBS += ole32.lib advapi32.lib rapi.lib + +include(qmake_include.pri) +include(bootstrapped.pri) +include($$QT_SOURCE_TREE/src/script/script.pri) + +INCLUDEPATH += $$QT_CE_RAPI_INC +LIBS += -L$$QT_CE_RAPI_LIB diff --git a/tools/qtestlib/wince/cetest/deployment.cpp b/tools/qtestlib/wince/cetest/deployment.cpp new file mode 100644 index 0000000..99ea532 --- /dev/null +++ b/tools/qtestlib/wince/cetest/deployment.cpp @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "deployment.h" +#include "remoteconnection.h" +#include <option.h> +#include <qdir.h> +#include <qfile.h> +#include <qstring.h> + +extern void debugOutput(const QString& text, int level); + +bool DeploymentHandler::deviceCopy(const DeploymentList &deploymentList) +{ + for (int i=0; i<deploymentList.size(); ++i) { + CopyItem item = deploymentList.at(i); + m_connection->createDirectory(item.to.left(item.to.lastIndexOf(QLatin1Char('\\')))); + if (!m_connection->copyFileToDevice(item.from , item.to)) { + debugOutput(QString::fromLatin1("Error while copy: %1 -> %2").arg(item.from).arg(item.to),0); + return false; + } + } + return true; +} + +bool DeploymentHandler::deviceDeploy(const DeploymentList &deploymentList) +{ + DeploymentList copyList; + for (int i=0; i<deploymentList.size(); ++i) { +#if defined(Q_OS_WIN) + HANDLE localHandle = CreateFile(deploymentList.at(i).from.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (localHandle == INVALID_HANDLE_VALUE) { + copyList.append(deploymentList.at(i)); + continue; + } + FILETIME localCreationTime; + if (!GetFileTime(localHandle, NULL, NULL, &localCreationTime) || !m_connection->timeStampForLocalFileTime(&localCreationTime)) { + copyList.append(deploymentList.at(i)); + CloseHandle(localHandle); + continue; + } + CloseHandle(localHandle); + + FILETIME deviceCreationTime; + if (!m_connection->fileCreationTime(deploymentList.at(i).to , &deviceCreationTime)) { + copyList.append(deploymentList.at(i)); + continue; + } + + int res = CompareFileTime(&localCreationTime, &deviceCreationTime); + if (res != 0) + copyList.append(deploymentList.at(i)); + else + debugOutput(QString::fromLatin1("Skipping File %1, already latest version").arg(deploymentList.at(i).from),0); +#else + copyList.append(deploymentList.at(i)); +#endif + } + return deviceCopy(copyList); +} + +void DeploymentHandler::cleanup(const DeploymentList &deploymentList) +{ + for (int i=0; i<deploymentList.size(); ++i) { + m_connection->deleteFile(deploymentList.at(i).to); +#ifdef Q_OS_WIN + QString path = deploymentList.at(i).to; + int pos; + while ( (pos = path.lastIndexOf(QLatin1Char('\\'))) > 0) { + path = path.left(pos); + if (!m_connection->deleteDirectory(path, false, true)) + break; + } +#endif + } +} + +void DeploymentHandler::initQtDeploy(QMakeProject *project, DeploymentList &deploymentList, const QString &testPath) +{ + QString targetPath = project->values("deploy.path").join(" "); + if (targetPath.isEmpty()) + targetPath = testPath; + if (targetPath.endsWith("/") || targetPath.endsWith("\\")) + targetPath = targetPath.mid(0,targetPath.size()-1); + + // Only deploy Qt libs for shared build + if (!project->values("QMAKE_QT_DLL").isEmpty() && !project->values("QMAKE_LIBDIR").isEmpty()) { + QStringList libs = project->values("LIBS"); + QStringList qtLibs; + foreach (QString item, libs) { + if (item.startsWith("-lQt")) { + qtLibs += project->values("QMAKE_LIBDIR").at(0) + QDir::separator() + item.mid(2) + QLatin1String("4.dll"); + } else { + QFileInfo info(item); + if (info.exists() && info.isAbsolute() && info.fileName().startsWith(QLatin1String("Qt"))) + qtLibs += info.dir().absoluteFilePath(info.fileName().replace(QLatin1String(".lib"), QLatin1String(".dll"))); + } + } + for (QStringList::ConstIterator it = qtLibs.constBegin(); it != qtLibs.constEnd(); ++it) { + QString dllName = *it; + QFileInfo info(dllName); + if (!info.exists()) + continue; + deploymentList.append(CopyItem(Option::fixPathToLocalOS(info.absoluteFilePath()) , + Option::fixPathToLocalOS(targetPath + "/" + info.fileName()))); + } + } + + // QtRemote deployment. We always deploy to \Windows + if (!project->values("QMAKE_LIBDIR").isEmpty()) { + QString remoteLibName = QLatin1String("QtRemote.dll"); + QString remoteLib = Option::fixPathToLocalOS(project->values("QMAKE_LIBDIR").at(0) + QDir::separator() + remoteLibName); + if (QFile::exists(remoteLib)) + deploymentList.append(CopyItem(remoteLib, QString::fromLatin1("\\Windows\\") + remoteLibName)); + else + debugOutput(QString::fromLatin1("Could not find QtRemote. Might not be able to launch target executable"),0); + } + + // C-runtime deployment + QString runtime = project->values("QT_CE_C_RUNTIME").join(QLatin1String(" ")); + debugOutput(QString::fromLatin1("Runtime:%1").arg(runtime), 2); + if (!runtime.isEmpty() && (runtime != QLatin1String("no"))) { + QString runtimeVersion = QLatin1String("msvcr"); + const QString mkspec = project->values("QMAKESPEC").first(); + if (mkspec.endsWith("2008")) + runtimeVersion.append("90"); + else + runtimeVersion.append("80"); + if (project->isActiveConfig("debug")) + runtimeVersion.append("d"); + runtimeVersion.append(".dll"); + + if (runtime == "yes") { + // Auto-find C-runtime + QString vcInstallDir = qgetenv("VCINSTALLDIR"); + if (!vcInstallDir.isEmpty()) { + vcInstallDir += "\\ce\\dll\\"; + vcInstallDir += project->values("CE_ARCH").join(QLatin1String(" ")); + if (!QFileInfo(vcInstallDir + QDir::separator() + runtimeVersion).exists()) + runtime.clear(); + else + runtime = vcInstallDir; + } + } + + if (!runtime.isEmpty()) { + deploymentList.append(CopyItem(Option::fixPathToLocalOS(runtime + "/" + runtimeVersion ) , + Option::fixPathToLocalOS(targetPath + "/" + runtimeVersion))); + } + } +} + +void DeploymentHandler::initProjectDeploy(QMakeProject* project, DeploymentList &deploymentList, const QString &testPath) +{ + QString targetPath = project->values("deploy.path").join(" "); + if (targetPath.isEmpty()) + targetPath = testPath; + if (targetPath.endsWith("/") || targetPath.endsWith("\\")) + targetPath = targetPath.mid(0,targetPath.size()-1); + + QStringList& list = project->values("DEPLOYMENT"); + if (list.isEmpty()) + return; + + for (int it = 0; it < list.size(); ++it) { + QString argSource = list.at(it) + QString(".sources"); + QString argPath = list.at(it) + QString(".path"); + if ((project->values(argSource).isEmpty() || project->values(argPath).isEmpty()) && list.at(it) != "deploy") { + debugOutput(QString::fromLatin1("cannot deploy \"%1\" because of missing data.").arg(list.at(it)), 0); + continue; + } + + QString addPath = project->values(argPath).join(QLatin1String(" ")); + if (addPath == QLatin1String(".")) + addPath.clear(); + if (!addPath.startsWith("/") && !addPath.startsWith(QLatin1String("\\"))) + addPath = targetPath + "/" + addPath; + + QStringList addSources = project->values(argSource); + addSources.replaceInStrings(QLatin1String("/"), QLatin1String("\\")); + for(int index=0; index < addSources.size(); ++index) { + QString dirstr = qmake_getpwd(); + QString filestr = Option::fixPathToLocalOS(addSources.at(index), false, false); + int slsh = filestr.lastIndexOf(Option::dir_sep); + if(slsh != -1) { + dirstr = filestr.left(slsh+1); + filestr = filestr.right(filestr.length() - slsh - 1); + } + if(dirstr.right(Option::dir_sep.length()) != Option::dir_sep) + dirstr += Option::dir_sep; + QFileInfo info(dirstr + filestr); + + static int addQMakeDeployCounter = 0; + QStringList entryList = info.absoluteDir().entryList(QStringList() << info.fileName()); + if (entryList.size() > 1) { + foreach(QString s, entryList) { + // We do not include directories when using wildcards + QFileInfo wildInfo(info.absolutePath() + "/" + s); + if (wildInfo.isDir()) { + continue; + } + QString appendedQmakeDeploy = QString::fromLatin1("_q_make_additional_deploy_%1").arg(addQMakeDeployCounter++); + project->parse(appendedQmakeDeploy + QLatin1String(".sources = \"") + wildInfo.absoluteFilePath()); + project->parse(appendedQmakeDeploy + QLatin1String(".path = \"") + addPath); + list.append(appendedQmakeDeploy); + } + continue; + } + + if (info.isDir()) { + QDir additionalDir(dirstr + filestr); + QStringList additionalEntries = additionalDir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::NoSymLinks); + foreach(QString item, additionalEntries) { + QString appendedDeploy = QString::fromLatin1("_q_make_additional_deploy_%1").arg(addQMakeDeployCounter++); + project->parse(appendedDeploy + QLatin1String(".sources = \"") + Option::fixPathToLocalOS(additionalDir.absoluteFilePath(item)) + QLatin1String("\"")); + QString appendTargetPath = project->values(argPath).join(QLatin1String(" ")); + if (appendTargetPath == QLatin1String(".")) + appendTargetPath = filestr; + else + appendTargetPath.append(QLatin1String("\\") + filestr); + project->parse(appendedDeploy + QLatin1String(".path = ") + appendTargetPath); + list.append(appendedDeploy); + } + } else if (entryList.size() == 1) + deploymentList.append(CopyItem(Option::fixPathToLocalOS(info.absolutePath() + "/" + entryList.at(0)) , + Option::fixPathToLocalOS(addPath + "/" + entryList.at(0)))); + } + } +} diff --git a/tools/qtestlib/wince/cetest/deployment.h b/tools/qtestlib/wince/cetest/deployment.h new file mode 100644 index 0000000..aa994ef --- /dev/null +++ b/tools/qtestlib/wince/cetest/deployment.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEPLOYMENT_INCL +#define DEPLOYMENT_INCL + +#include <qstring.h> +#include <qlist.h> +#include <project.h> + +class AbstractRemoteConnection; + +struct CopyItem +{ + CopyItem(const QString& f, const QString& t) : from(f) , to(t) { } + QString from; + QString to; +}; +typedef QList<CopyItem> DeploymentList; + +class DeploymentHandler +{ +public: + inline void setConnection(AbstractRemoteConnection*); + inline AbstractRemoteConnection* connection() const; + bool deviceCopy(const DeploymentList &deploymentList); + bool deviceDeploy(const DeploymentList &deploymentList); + void cleanup(const DeploymentList &deploymentList); + static void initProjectDeploy(QMakeProject* project, DeploymentList &deploymentList, const QString &testPath = "\\Program Files\\qt_test"); + static void initQtDeploy(QMakeProject* project, DeploymentList &deploymentList, const QString &testPath = "\\Program Files\\qt_test"); +private: + AbstractRemoteConnection* m_connection; +}; + +inline void DeploymentHandler::setConnection(AbstractRemoteConnection *connection) { m_connection = connection; } +inline AbstractRemoteConnection* DeploymentHandler::connection() const { return m_connection; } +#endif
\ No newline at end of file diff --git a/tools/qtestlib/wince/cetest/main.cpp b/tools/qtestlib/wince/cetest/main.cpp new file mode 100644 index 0000000..17f6810 --- /dev/null +++ b/tools/qtestlib/wince/cetest/main.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "activesyncconnection.h" +#include "deployment.h" +#include <option.h> +#include <project.h> +#include <property.h> +#include <qstringlist.h> +#include <qfileinfo.h> +#include <qdir.h> +#include <iostream> +using namespace std; + +const int debugLevel = 0; +void debugOutput(const QString& text, int level) +{ + if (level <= debugLevel) + cout << qPrintable(text) << endl; +} + +// needed for QMake sources to compile +QString project_builtin_regx() { return QString();} +static QString pwd; +QString qmake_getpwd() +{ + if(pwd.isNull()) + pwd = QDir::currentPath(); + return pwd; +} +bool qmake_setpwd(const QString &p) +{ + if(QDir::setCurrent(p)) { + pwd = QDir::currentPath(); + return true; + } + return false; +} + +namespace TestConfiguration { + QString localExecutable; + QString localQtConf; + QString remoteTestPath; + QString remoteLibraryPath; + QString remoteExecutable; + QString remoteResultFile; + + bool testDebug; + void init() + { + testDebug = true; + localQtConf = QLatin1String("no"); + remoteTestPath = QLatin1String("\\Program Files\\qt_test"); + remoteLibraryPath = remoteTestPath; + remoteResultFile = QLatin1String("\\qt_test_results.txt"); + } +} + +void usage() +{ + cout << + "QTestLib options\n" + " -functions : Returns a list of current testfunctions\n" + " -xml : Outputs results as XML document\n" + " -lightxml : Outputs results as stream of XML tags\n" + " -o filename: Writes all output into a file\n" + " -silent : Only outputs warnings and failures\n" + " -v1 : Print enter messages for each testfunction\n" + " -v2 : Also print out each QVERIFY/QCOMPARE/QTEST\n" + " -vs : Print every signal emitted\n" + " -eventdelay ms : Set default delay for mouse and keyboard simulation to ms milliseconds\n" + " -keydelay ms : Set default delay for keyboard simulation to ms milliseconds\n" + " -mousedelay ms : Set default delay for mouse simulation to ms milliseconds\n" + " -keyevent-verbose : Turn on verbose messages for keyboard simulation\n" + " -maxwarnings n : Sets the maximum amount of messages to output.\n" + " 0 means unlimited, default: 2000\n" + " -help : This help\n"; + cout << + "cetest specific options\n" + " -debug : Test debug version[default]\n" + " -release : Test release version\n" + " -libpath <path> : Remote path to deploy Qt libraries to\n" + " -qt-delete : Delete the Qt libraries after execution\n" + " -project-delete : Delete the project file(s) after execution\n" + " -delete : Delete everything deployed after execution\n" + " -conf : Specify location of qt.conf file\n" + " -f <file> : Specify project file\n" + " -cache <file> : Specify .qmake.cache file to use\n" + " -timeout <value> : Specify a timeout value after which the test will be terminated\n" + " -1 specifies waiting forever (default)\n" + " 0 specifies starting the process detached\n" + " >0 wait <value> seconds\n" + "\n"; +} + +int main(int argc, char **argv) +{ + QStringList arguments; + for (int i=0; i<argc; ++i) + arguments.append(QString::fromLatin1(argv[i])); + + TestConfiguration::init(); + + QStringList launchArguments; + QString resultFile; + QString proFile; + QString cacheFile; + int timeout = -1; + bool cleanupQt = false; + bool cleanupProject = false; + + for (int i=1; i<arguments.size(); ++i) { + if (arguments.at(i).toLower() == QLatin1String("-help") + || arguments.at(i).toLower() == QLatin1String("--help") + || arguments.at(i).toLower() == QLatin1String("/?")) { + usage(); + return 0; + } else if (arguments.at(i).toLower() == QLatin1String("-o")) { + if (++i == arguments.size()) { + cout << "Error: No output file specified!" << endl; + return -1; + } + resultFile = arguments.at(i); + } else if (arguments.at(i).toLower() == QLatin1String("-eventdelay") + || arguments.at(i).toLower() == QLatin1String("-keydelay") + || arguments.at(i).toLower() == QLatin1String("-mousedelay") + || arguments.at(i).toLower() == QLatin1String("-maxwarnings")) { + launchArguments.append(arguments.at(i++)); + if (i == arguments.size()) { + cout << "Please specify value for:" << qPrintable(arguments.at(i-1).mid(1)) << endl; + return -1; + } + launchArguments.append(arguments.at(i)); + } else if (arguments.at(i).toLower() == QLatin1String("-debug")) { + TestConfiguration::testDebug = true; + Option::before_user_vars.append("CONFIG-=release"); + Option::before_user_vars.append("CONFIG+=debug"); + } else if (arguments.at(i).toLower() == QLatin1String("-release")) { + TestConfiguration::testDebug = false; + Option::before_user_vars.append("CONFIG-=debug"); + Option::before_user_vars.append("CONFIG+=release"); + } else if (arguments.at(i).toLower() == QLatin1String("-libpath")) { + if (++i == arguments.size()) { + cout << "Error: No library path specified!" << endl; + return -1; + } + TestConfiguration::remoteLibraryPath = arguments.at(i); + } else if (arguments.at(i).toLower() == QLatin1String("-qt-delete")) { + cleanupQt = true; + } else if (arguments.at(i).toLower() == QLatin1String("-project-delete")) { + cleanupProject = true; + } else if (arguments.at(i).toLower() == QLatin1String("-delete")) { + cleanupQt = true; + cleanupProject = true; + } else if (arguments.at(i).toLower() == QLatin1String("-conf")) { + if (++i == arguments.size()) { + cout << "Error: No qt.conf file specified!" << endl; + return -1; + } + if (!QFileInfo(arguments.at(i)).exists()) + cout << "Warning: could not find qt.conf file at:" << qPrintable(arguments.at(i)) << endl; + else + TestConfiguration::localQtConf = arguments.at(i); + } else if (arguments.at(i).toLower() == QLatin1String("-f")) { + if (++i == arguments.size()) { + cout << "Error: No output file specified!" << endl; + return -1; + } + proFile = arguments.at(i); + } else if (arguments.at(i).toLower() == QLatin1String("-cache")) { + if (++i == arguments.size()) { + cout << "Error: No cache file specified!" << endl; + return -1; + } + cacheFile = arguments.at(i); + } else if (arguments.at(i).toLower() == QLatin1String("-timeout")) { + if (++i == arguments.size()) { + cout << "Error: No timeout value specified!" << endl; + return -1; + } + timeout = QString(arguments.at(i)).toInt(); + } else { + launchArguments.append(arguments.at(i)); + } + } + + // check for .pro file + if (proFile.isEmpty()) { + proFile = QDir::current().dirName() + QLatin1String(".pro"); + if (!QFileInfo(proFile).exists()) { + cout << "Error: Could not find project file in current directory." << endl; + return -1; + } + debugOutput(QString::fromLatin1("Using Project File:").append(proFile),1); + } + + // read target and deployment rules + int qmakeArgc = 1; + char* qmakeArgv[] = { "qmake.exe" }; + Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING; + Option::output_dir = qmake_getpwd(); + if (!cacheFile.isEmpty()) + Option::mkfile::cachefile = cacheFile; + int ret = Option::init(qmakeArgc, qmakeArgv); + if(ret != Option::QMAKE_CMDLINE_SUCCESS) { + cout << "Error: could not parse " << qPrintable(proFile) << endl; + return -1; + } + + QMakeProperty prop; + QMakeProject project(&prop); + + project.read(proFile); + if (project.values("TEMPLATE").join(" ").toLower() != QString("app")) { + cout << "Error: Can only test executables!" << endl; + return -1; + } + // Check wether the project is still in debug/release mode after reading + // If .pro specifies to be one mode only, we need to accept this + if (project.isActiveConfig("debug")) + TestConfiguration::testDebug = true; + else + TestConfiguration::testDebug = false; + + QString destDir = project.values("DESTDIR").join(" "); + if (!destDir.isEmpty()) { + if (QDir::isRelativePath(destDir)) { + QFileInfo fi(proFile); + if (destDir == QLatin1String(".")) + destDir = fi.absolutePath() + "/" + destDir + "/" + (TestConfiguration::testDebug ? "debug" : "release"); + else + destDir = fi.absolutePath() + QDir::separator() + destDir; + } + } else { + QFileInfo fi(proFile); + destDir = fi.absolutePath(); + destDir += QDir::separator() + QLatin1String(TestConfiguration::testDebug ? "debug" : "release"); + } + + DeploymentList qtDeploymentList; + DeploymentList projectDeploymentList; + + TestConfiguration::localExecutable = Option::fixPathToLocalOS(destDir + QDir::separator() + project.values("TARGET").join(" ") + QLatin1String(".exe")); + TestConfiguration::remoteTestPath = QLatin1String("\\Program Files\\") + Option::fixPathToLocalOS(project.values("TARGET").join(QLatin1String(" "))); + if (!arguments.contains(QLatin1String("-libpath"), Qt::CaseInsensitive)) + TestConfiguration::remoteLibraryPath = TestConfiguration::remoteTestPath; + + QString targetExecutable = Option::fixPathToLocalOS(project.values("TARGET").join(QLatin1String(" "))); + int last = targetExecutable.lastIndexOf(QLatin1Char('\\')); + targetExecutable = targetExecutable.mid( last == -1 ? 0 : last+1 ); + TestConfiguration::remoteExecutable = TestConfiguration::remoteTestPath + QDir::separator() + targetExecutable + QLatin1String(".exe"); + projectDeploymentList.append(CopyItem(TestConfiguration::localExecutable , TestConfiguration::remoteExecutable)); + + // deploy + ActiveSyncConnection connection; + if (!connection.connect()) { + cout << "Error: Could not connect to device!" << endl; + return -1; + } + DeploymentHandler deployment; + deployment.setConnection(&connection); + + deployment.initQtDeploy(&project, qtDeploymentList, TestConfiguration::remoteLibraryPath); + deployment.initProjectDeploy(&project , projectDeploymentList, TestConfiguration::remoteTestPath); + + // add qt.conf + if (TestConfiguration::localQtConf != QLatin1String("no")) { + QString qtConfOrigin = QFileInfo(TestConfiguration::localQtConf).absoluteFilePath(); + QString qtConfTarget = Option::fixPathToLocalOS(TestConfiguration::remoteTestPath + QDir::separator() + QLatin1String("qt.conf")); + projectDeploymentList.append(CopyItem(qtConfOrigin, qtConfTarget)); + } + + if (!deployment.deviceDeploy(qtDeploymentList) || !deployment.deviceDeploy(projectDeploymentList)) { + cout << "Error: Could not copy file(s) to device" << endl; + return -1; + } + + // launch + launchArguments.append("-o"); + launchArguments.append(TestConfiguration::remoteResultFile); + + cout << endl << "Remote Launch:" << qPrintable(TestConfiguration::remoteExecutable) << " " << qPrintable(launchArguments.join(" ")) << endl; + if (!connection.execute(TestConfiguration::remoteExecutable, launchArguments.join(" "), timeout)) { + cout << "Error: Could not execute target file" << endl; + } + + + // copy result file + // show results + if (resultFile.isEmpty()) { + QString tempResultFile = Option::fixPathToLocalOS(QDir::tempPath() + "/qt_ce_temp_result_file.txt"); + if (connection.copyFileFromDevice(TestConfiguration::remoteResultFile, tempResultFile)) { + QFile file(tempResultFile); + QByteArray arr; + if (file.open(QIODevice::ReadOnly)) { + arr = file.readAll(); + cout << arr.constData() << endl; + } + file.close(); + file.remove(); + } + } else { + connection.copyFileFromDevice(TestConfiguration::remoteResultFile, resultFile); + } + + // delete + connection.deleteFile(TestConfiguration::remoteResultFile); + if (cleanupQt) + deployment.cleanup(qtDeploymentList); + if (cleanupProject) + deployment.cleanup(projectDeploymentList); + return 0; +} diff --git a/tools/qtestlib/wince/cetest/qmake_include.pri b/tools/qtestlib/wince/cetest/qmake_include.pri new file mode 100644 index 0000000..3831634 --- /dev/null +++ b/tools/qtestlib/wince/cetest/qmake_include.pri @@ -0,0 +1,7 @@ +#qmake source files needed for cetest +HEADERS += \ + $$QT_SOURCE_TREE/qmake/option.h +SOURCES += \ + $$QT_SOURCE_TREE/qmake/option.cpp \ + $$QT_SOURCE_TREE/qmake/project.cpp \ + $$QT_SOURCE_TREE/qmake/property.cpp diff --git a/tools/qtestlib/wince/cetest/remoteconnection.cpp b/tools/qtestlib/wince/cetest/remoteconnection.cpp new file mode 100644 index 0000000..7033ed6 --- /dev/null +++ b/tools/qtestlib/wince/cetest/remoteconnection.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "remoteconnection.h" + +AbstractRemoteConnection::AbstractRemoteConnection() +{ +} + +AbstractRemoteConnection::~AbstractRemoteConnection() +{ +} + + +// Slow but should be ok... +bool AbstractRemoteConnection::moveFile(const QString &src, const QString &dest, bool FailIfExists) +{ + bool result = copyFile(src, dest, FailIfExists); + deleteFile(src); + return result; +} + +// Slow but should be ok... +bool AbstractRemoteConnection::moveDirectory(const QString &src, const QString &dest, bool recursive) +{ + bool result = copyDirectory(src, dest, true); + deleteDirectory(src, recursive); + return result; +} + diff --git a/tools/qtestlib/wince/cetest/remoteconnection.h b/tools/qtestlib/wince/cetest/remoteconnection.h new file mode 100644 index 0000000..8e8b3fd --- /dev/null +++ b/tools/qtestlib/wince/cetest/remoteconnection.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REMOTECONNECTION_H +#define REMOTECONNECTION_H + +#include <QtCore/QString> +#include <QtCore/QVariant> +#include <windows.h> +class AbstractRemoteConnection +{ +public: + AbstractRemoteConnection(); + virtual ~AbstractRemoteConnection(); + + virtual bool connect(QVariantList&) = 0; + virtual void disconnect() = 0; + virtual bool isConnected() const = 0; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + virtual bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false) = 0; + virtual bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true) = 0; + virtual bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false) = 0; + virtual bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true) = 0; + + // For "intelligent deployment" we need to investigate on filetimes on the device + virtual bool timeStampForLocalFileTime(FILETIME*) const = 0; + virtual bool fileCreationTime(const QString &fileName, FILETIME*) const = 0; + + // These functions only work on files existing on the device + virtual bool copyFile(const QString&, const QString&, bool failIfExists = false) = 0; + virtual bool copyDirectory(const QString&, const QString&, bool recursive = true) = 0; + virtual bool deleteFile(const QString&) = 0; + virtual bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false) = 0; + bool moveFile(const QString&, const QString&, bool FailIfExists = false); + bool moveDirectory(const QString&, const QString&, bool recursive = true); + + virtual bool createDirectory(const QString&, bool deleteBefore=false) = 0; + + virtual bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL) = 0; +}; + +#endif diff --git a/tools/qtestlib/wince/remotelib/commands.cpp b/tools/qtestlib/wince/remotelib/commands.cpp new file mode 100644 index 0000000..f611317 --- /dev/null +++ b/tools/qtestlib/wince/remotelib/commands.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "commands.h" + +#define CLEAN_FAIL(a) {delete appName; \ + delete arguments; \ + return (a); } + +int qRemoteLaunch(DWORD, BYTE*, DWORD*, BYTE**, IRAPIStream* stream) +{ + if (!stream) + return -1; + + DWORD bytesRead; + int appLength; + wchar_t* appName = 0; + int argumentsLength; + wchar_t* arguments = 0; + int timeout = -1; + int returnValue = -2; + + if (S_OK != stream->Read(&appLength, sizeof(appLength), &bytesRead)) + CLEAN_FAIL(-2); + appName = (wchar_t*) malloc(sizeof(wchar_t)*(appLength + 1)); + if (S_OK != stream->Read(appName, sizeof(wchar_t)*appLength, &bytesRead)) + CLEAN_FAIL(-2); + appName[appLength] = '\0'; + + if (S_OK != stream->Read(&argumentsLength, sizeof(argumentsLength), &bytesRead)) + CLEAN_FAIL(-2); + arguments = (wchar_t*) malloc(sizeof(wchar_t)*(argumentsLength + 1)); + if (S_OK != stream->Read(arguments, sizeof(wchar_t)*argumentsLength, &bytesRead)) + CLEAN_FAIL(-2); + arguments[argumentsLength] = '\0'; + + if (S_OK != stream->Read(&timeout, sizeof(timeout), &bytesRead)) + CLEAN_FAIL(-2); + + bool result = qRemoteExecute(appName, arguments, &returnValue, timeout); + + if (timeout != 0) { + if (S_OK != stream->Write(&returnValue, sizeof(returnValue), &bytesRead)) + CLEAN_FAIL(-4); + } + delete appName; + delete arguments; + // We need to fail here for the execute, otherwise the calling application will wait + // forever for the returnValue. + if (!result) + return -3; + return S_OK; +} + + +bool qRemoteExecute(const wchar_t* program, const wchar_t* arguments, int *returnValue, int timeout) +{ + if (!program) + return false; + + PROCESS_INFORMATION pid; + if (!CreateProcess(program, arguments, NULL, NULL, false, 0, NULL, NULL, NULL, &pid)) { + wprintf(L"Could not launch: %s\n", program); + return false; + } + + // Timeout is in seconds + DWORD waitingTime = (timeout == -1) ? INFINITE : timeout * 1000; + + if (waitingTime != 0) { + DWORD waitStatus = WaitForSingleObject(pid.hProcess, waitingTime); + if (waitStatus == WAIT_TIMEOUT) { + TerminateProcess(pid.hProcess, 2); + return false; + } else if (waitStatus == WAIT_OBJECT_0 && returnValue) { + *returnValue = 0; + DWORD exitCode; + if (GetExitCodeProcess(pid.hProcess, &exitCode)) + *returnValue = exitCode; + } + } + return true; +} diff --git a/tools/qtestlib/wince/remotelib/commands.h b/tools/qtestlib/wince/remotelib/commands.h new file mode 100644 index 0000000..80a6f13 --- /dev/null +++ b/tools/qtestlib/wince/remotelib/commands.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QREMOTECOMMANDS_H +#define QREMOTECOMMANDS_H +#include <winbase.h> +#include <rapi.h> + +extern "C" { + int __declspec(dllexport) qRemoteLaunch(DWORD, BYTE*, DWORD*, BYTE**, IRAPIStream*); + bool __declspec(dllexport) qRemoteExecute(const wchar_t* program, const wchar_t* arguments = NULL, int *returnValue = NULL , int timeout = -1); +} + +#endif diff --git a/tools/qtestlib/wince/remotelib/remotelib.pro b/tools/qtestlib/wince/remotelib/remotelib.pro new file mode 100644 index 0000000..dc61c7f --- /dev/null +++ b/tools/qtestlib/wince/remotelib/remotelib.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +CONFIG += dll +CONFIG -= staticlib +TARGET = QtRemote +DESTDIR = ../../../../lib +DEPENDPATH += . +INCLUDEPATH += . +QT = +# Input +HEADERS += commands.h +SOURCES += commands.cpp + +INCLUDEPATH += $$QT_CE_RAPI_INC +LIBS += -L$$QT_CE_RAPI_LIB + diff --git a/tools/qtestlib/wince/wince.pro b/tools/qtestlib/wince/wince.pro new file mode 100644 index 0000000..7c88d65 --- /dev/null +++ b/tools/qtestlib/wince/wince.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +wince*:SUBDIRS = remotelib
\ No newline at end of file |