From 76dd2cd2942c219b7619a84dc5eaa142d67fc28a Mon Sep 17 00:00:00 2001 From: Filip Bucek Date: Tue, 5 Nov 2019 09:25:02 +0100 Subject: [PATCH] initial commit --- .gitlab-ci.yml | 32 ++++++++++ core-sdk.pro | 10 +++ src/core/compression.cpp | 113 +++++++++++++++++++++++++++++++++ src/core/compression.h | 19 ++++++ src/core/core.pri | 21 ++++++ src/core/databasemanager.cpp | 56 ++++++++++++++++ src/core/databasemanager.h | 37 +++++++++++ src/core/logger.cpp | 104 ++++++++++++++++++++++++++++++ src/core/logger.h | 42 ++++++++++++ src/core/loggermessage.cpp | 64 +++++++++++++++++++ src/core/loggermessage.h | 36 +++++++++++ src/core/request.cpp | 103 ++++++++++++++++++++++++++++++ src/core/request.h | 58 +++++++++++++++++ src/core/requestmanager.cpp | 95 +++++++++++++++++++++++++++ src/core/requestmanager.h | 42 ++++++++++++ src/core/zlib.pri | 8 +++ src/lib/lib.pro | 5 ++ src/testapp/app.pro | 6 ++ src/testapp/main.cpp | 20 ++++++ src/testapp/testapp.pro | 7 ++ test/test.pro | 5 ++ test/unittests/tst_request.cpp | 19 ++++++ test/unittests/tst_request.h | 21 ++++++ test/unittests/unittests.pro | 14 ++++ 24 files changed, 937 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 core-sdk.pro create mode 100644 src/core/compression.cpp create mode 100644 src/core/compression.h create mode 100644 src/core/core.pri create mode 100644 src/core/databasemanager.cpp create mode 100644 src/core/databasemanager.h create mode 100644 src/core/logger.cpp create mode 100644 src/core/logger.h create mode 100644 src/core/loggermessage.cpp create mode 100644 src/core/loggermessage.h create mode 100644 src/core/request.cpp create mode 100644 src/core/request.h create mode 100644 src/core/requestmanager.cpp create mode 100644 src/core/requestmanager.h create mode 100644 src/core/zlib.pri create mode 100644 src/lib/lib.pro create mode 100644 src/testapp/app.pro create mode 100644 src/testapp/main.cpp create mode 100644 src/testapp/testapp.pro create mode 100644 test/test.pro create mode 100644 test/unittests/tst_request.cpp create mode 100644 test/unittests/tst_request.h create mode 100644 test/unittests/unittests.pro diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..503e0a7 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,32 @@ +# for +stages: +- build +- test + +# ######## +# Build +########## +build: # name of task + stage: build # in what stage it will run ( 1. build then test etc ) + tags: # Tags are used to choose correct gitlab-runner + - hw # spaceti-runner server has running runners and one has tag 'hw' + script: # run in bash + - mkdir -p build + - cd build + - qmake ../core-sdk.pro + - make -j8 +cache: + paths: + - build/ + + +# ######## +# Test +########## +test: # name of task + stage: test # in what stage it will run ( 1. build then test etc ) + tags: # Tags are used to choose correct gitlab-runner + - hw # spaceti-runner server has running runners and one has tag 'hw' + script: # run in bash + - cd build + - make check test diff --git a/core-sdk.pro b/core-sdk.pro new file mode 100644 index 0000000..264bf3d --- /dev/null +++ b/core-sdk.pro @@ -0,0 +1,10 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + src/lib \ + src/testapp \ + test \ + + +OTHER_FILES += \ + .gitlab-ci.yml diff --git a/src/core/compression.cpp b/src/core/compression.cpp new file mode 100644 index 0000000..bbc6939 --- /dev/null +++ b/src/core/compression.cpp @@ -0,0 +1,113 @@ +#include "compression.h" + +#include +#include + +#include // gzip decompress + + +namespace core { + +/** + * @brief Decompress gzip data + * @param compressed gzip data + * @return decompressed data + */ +QByteArray Compression::decompress(const QByteArray &compressed) +{ + if (compressed.size() <= 4) { + qWarning("gUncompress: Input data is truncated"); + return QByteArray(); + } + + QByteArray result; + + int ret; + z_stream strm; + static const int CHUNK_SIZE = 1024; + char out[CHUNK_SIZE]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = compressed.size(); + strm.next_in = (Bytef*)(compressed.data()); + + ret = inflateInit2(&strm, 15 + 32); // gzip decoding + if (ret != Z_OK) + return QByteArray(); + + // run inflate() + do { + strm.avail_out = CHUNK_SIZE; + strm.next_out = (Bytef*)(out); + + ret = inflate(&strm, Z_NO_FLUSH); + Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered + + switch (ret) { + case Z_NEED_DICT: + return QByteArray(); + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return QByteArray(); + } + + result.append(out, CHUNK_SIZE - strm.avail_out); + } while (strm.avail_out == 0); + + // clean up and return + inflateEnd(&strm); + + // Calculate compression ratio + // original :200 + // compressed :100 + // ratio = 0.5 + float ratio = (float)compressed.count() / (float)result.count(); + float compression = ratio * 100.0; + + qCInfo(sdkcompress) << "compress data:" << compressed.count() + << "uncompressed data:" << result.count() + << "compression:" << compression; + + return result; +} + +/** + * @brief Return path to source directory + * @param subpath ( e.g. test/data ) + * @return absolute path to desired subpath in source folder + */ +QString Compression::sourcePath(const QString &subpath) +{ + QDir dir(__FILE__); + dir.cdUp(); + dir.cdUp(); + dir.cdUp(); + + return dir.absoluteFilePath(subpath); +} + +/** + * @brief Return data from source directory + * @param subpath ( e.g. test/data/gizp.src ) + * @return data of file - QByteArray + */ +QByteArray Compression::sourceData(const QString &subpath) +{ + // Get data from file + QString filePath = sourcePath(subpath); + if (! QFileInfo::exists(filePath)) { + qCWarning(sdkcompress) << "path does not exists:" << filePath; + return QByteArray(); + } + QFile file(filePath); + if ( file.open(QIODevice::ReadOnly) ) + return file.readAll(); + return QByteArray(); +} + + +} // namespace core diff --git a/src/core/compression.h b/src/core/compression.h new file mode 100644 index 0000000..4ebc89d --- /dev/null +++ b/src/core/compression.h @@ -0,0 +1,19 @@ +#pragma once + +#include "logger.h" + +#include + +namespace core { + +class Compression +{ +public: + static QByteArray decompress(const QByteArray &compressed); + + static QString sourcePath(const QString &subpath); + static QByteArray sourceData(const QString &subpath); +}; + +} // namespace core + diff --git a/src/core/core.pri b/src/core/core.pri new file mode 100644 index 0000000..3bba75e --- /dev/null +++ b/src/core/core.pri @@ -0,0 +1,21 @@ +INCLUDEPATH += $$PWD +CONFIG += c++14 +#SRC_DIR = $$PWD +message($$PWD) +SOURCES += \ + $$PWD/databasemanager.cpp \ + $$PWD/logger.cpp \ + $$PWD/loggermessage.cpp \ + $$PWD/requestmanager.cpp \ + $$PWD/request.cpp \ + +HEADERS += \ + $$PWD/databasemanager.h \ + $$PWD/logger.h \ + $$PWD/loggermessage.h \ + $$PWD/requestmanager.h \ + $$PWD/request.h \ + + +# TODO: implement zlib compression +# include (zlib.pri) diff --git a/src/core/databasemanager.cpp b/src/core/databasemanager.cpp new file mode 100644 index 0000000..bf891cb --- /dev/null +++ b/src/core/databasemanager.cpp @@ -0,0 +1,56 @@ +#include "databasemanager.h" + +namespace core { + +DatabaseManager::DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password, bool dryMode) + : mDryMode(dryMode) +{ + db = QSqlDatabase::addDatabase("QPSQL"); + db.setDatabaseName(dbName); + db.setHostName(host); + db.setUserName(user); // home-office stuff -->> db.setPort(80); + db.setPassword(password); + if (db.open()) + { + query = QSqlQuery("query", db); + } else { + log("Opening error" + db.lastError().text()); + emit error(); + } +} + +bool DatabaseManager::executeQuery(QSqlQuery &query) +{ + if (mDryMode){ + QString sqlStatement = getLastQuery(query); + qDebug() << sqlStatement; + + } + if (!mDryMode || query.isSelect()){ + if (!query.exec()){ + QString msg = QString("Source: Database Manager, Error: %1").arg(query.lastError().text()); + log(QString(msg)); + emit error(); + } + } + return true; +} + +QString DatabaseManager::getLastQuery(const QSqlQuery& query) const +{ + QString str = query.lastQuery(); + QMapIterator it(query.boundValues()); + while (it.hasNext()) + { + it.next(); + str.replace(it.key(),it.value().toString()); + } + return str; +} + +void DatabaseManager::log(const QString &msg) const +{ + qDebug("database logger implement logger"); +} + +} // core diff --git a/src/core/databasemanager.h b/src/core/databasemanager.h new file mode 100644 index 0000000..3232b3d --- /dev/null +++ b/src/core/databasemanager.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +//#include "logger.h" + +namespace core { + +class DatabaseManager : public QObject +{ + Q_OBJECT + friend class Logger; +public: + DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password, bool mDryMode = false); + +private: + bool executeQuery(QSqlQuery &query); + QString getLastQuery(const QSqlQuery &query) const; + + void log(const QString &msg) const; + +signals: + void error(); + +private: + QSqlDatabase db; + QSqlQuery query; + bool mDryMode = false; +}; + +} // core diff --git a/src/core/logger.cpp b/src/core/logger.cpp new file mode 100644 index 0000000..7c8df44 --- /dev/null +++ b/src/core/logger.cpp @@ -0,0 +1,104 @@ +#include "logger.h" +#include "loggermessage.h" + +#include + +Q_LOGGING_CATEGORY(sdkcore, "sdk.core"); +Q_LOGGING_CATEGORY(sdknetwork, "sdk.network"); +Q_LOGGING_CATEGORY(sdkcompress, "sdk.compress"); + +namespace core { + +Logger* Logger::sConsumer = nullptr; +//bool Logger::sShowFunction = false; + +/** + * @brief Used to have user specific consumer of logger messages + * @param consumer - inv::Logger + */ +void Logger::setConsumer(Logger *consumer) +{ + sConsumer = consumer; +} + +Logger::Logger(QObject *parent) : QObject(parent) +{ + qRegisterMetaType(); +} + +QList Logger::getNewMessages(int currentCount) +{ + QMutexLocker locker(&mMutex); + QList list; + + int count = mLogMessages.count(); + int total = count - currentCount; + if (total <= 0) + return list; + + for (int i = 0; i < total; ++i) { + int currentIndex = currentCount; + int row = i + currentIndex; + list.append(mLogMessages.at(row)); + } + return list; +} + + +void Logger::outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + QString shortFile = QFileInfo(context.file).fileName(); + + QString text; + QString textType; + + switch (type) { + case QtDebugMsg: + textType = QStringLiteral("debug"); + break; + case QtWarningMsg: + textType = QStringLiteral("warning"); + break; + case QtCriticalMsg: + textType = QStringLiteral("critical"); + break; + case QtFatalMsg: + textType = QStringLiteral("fatal"); + break; +#if QT_VERSION >= 0x050500 + case QtInfoMsg: + textType = QStringLiteral("info"); + break; +#endif + } + if (sConsumer) { + LoggerMessage logmsg(shortFile,context.line,context.function,textType,context.category,msg, QLatin1String("")); + sConsumer->insertMessage(logmsg); // emiting message + } + + // Output message + //text += QString("%1 %2:%3 %4").arg(context.category).arg(shortFile).arg(context.line).arg(msg); + // New output syntax + text = QStringLiteral("[%1] %2 [ %3:%4 | %5 | %6 ]") + .arg(textType, msg, shortFile) + .arg(context.line) + .arg(context.function, context.category); + + QTextStream out(stderr); + out << text << "\n"; //.toLocal8Bit() + "\n"; + //out.flush(); // INVSDK-37 ORK-102 crash on windows when flush() -> possible threading problem + + if (type == QtFatalMsg) + abort(); +} + +void Logger::insertMessage(const LoggerMessage& logmsg) +{ + emit sConsumer->messageReceived(logmsg); + QMutexLocker locker(&sConsumer->mMutex); + sConsumer->mLogMessages.append(logmsg); + emit sConsumer->messageListUpdated(); +} + +} // core + diff --git a/src/core/logger.h b/src/core/logger.h new file mode 100644 index 0000000..bef4614 --- /dev/null +++ b/src/core/logger.h @@ -0,0 +1,42 @@ +#pragma once + +#include "loggermessage.h" + +// Qt +#include +#include +#include + + +Q_DECLARE_LOGGING_CATEGORY(sdkcore) +Q_DECLARE_LOGGING_CATEGORY(sdknetwork) +Q_DECLARE_LOGGING_CATEGORY(sdkcompress) + +namespace core { + +/** @see http://stackoverflow.com/questions/8337300/c11-how-do-i-implement-convenient-logging-without-a-singleton */ +class Logger : public QObject +{ + Q_OBJECT +public: + // Static methods + static Logger* sConsumer; + static void setConsumer(Logger *consumer); + static void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg); +// static void message(const char *file, int line, const char *function, const QString &type, const QString &group, const QString &msg, const QString &detail = QString()); + // Public methods + explicit Logger(QObject *parent = nullptr); + void insertMessage(const LoggerMessage& logmsg); + QList getNewMessages(int currentCount); + + +signals: + void messageReceived(const core::LoggerMessage &message); + void messageListUpdated(); +private: + QList mLogMessages; + QMutex mMutex; +}; + + +} // core diff --git a/src/core/loggermessage.cpp b/src/core/loggermessage.cpp new file mode 100644 index 0000000..f1a14c8 --- /dev/null +++ b/src/core/loggermessage.cpp @@ -0,0 +1,64 @@ +#include "loggermessage.h" + +#include +#include + +#include + +namespace core { + +LoggerMessage::LoggerMessage(QString file, int line, QString function, QString type, QString group, QString msg, QString detailMessage) + : mFile(std::move(file)), mFunction(std::move(function)), mType(std::move(type)), mLine(line), + mGroup(std::move(group)), mMessage(std::move(msg)), mDetailMessage(std::move(detailMessage)) +{ +} + +QString LoggerMessage::shortFile() const +{ + return QFileInfo(mFile).fileName(); +} + +QString LoggerMessage::type() const +{ + return mType; +} + +QString LoggerMessage::file() const +{ + return mFile; +} + +int LoggerMessage::line() const +{ + return mLine; +} + +QString LoggerMessage::group() const +{ + return mGroup; +} + +QString LoggerMessage::message() const +{ + return mMessage; +} + +QString LoggerMessage::detail() const +{ + return mDetailMessage; +} + +QString LoggerMessage::function() const +{ + return mFunction; +} + +} // core + + +QDebug operator<<(QDebug dbg, const core::LoggerMessage &message) +{ + dbg.nospace() << "message: " << message.message(); + dbg.nospace() << "next output not implemented: " << message.message(); + return dbg; +} diff --git a/src/core/loggermessage.h b/src/core/loggermessage.h new file mode 100644 index 0000000..cdef6d7 --- /dev/null +++ b/src/core/loggermessage.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +namespace core { + +class LoggerMessage +{ +public: + LoggerMessage() = default; + LoggerMessage(QString file, int line, QString function, QString type, QString group, QString msg, QString detailMessage = QString()); + QString shortFile() const; + QString type() const; + QString file() const; + int line() const; + QString group() const; + QString message() const; + QString detail() const; + QString function() const; + +private: + QString mFile; + QString mFunction; + QString mType; + int mLine = -1; + QString mGroup; + QString mMessage; + QString mDetailMessage; +}; + +} // core + +QDebug operator<<(QDebug dbg, const core::LoggerMessage &message); + +Q_DECLARE_METATYPE(core::LoggerMessage) diff --git a/src/core/request.cpp b/src/core/request.cpp new file mode 100644 index 0000000..4a5d849 --- /dev/null +++ b/src/core/request.cpp @@ -0,0 +1,103 @@ +#include "request.h" +#include "logger.h" +#include "requestmanager.h" // to get logger class +#include +#include + +namespace core { + + +Request::~Request() +{ +} + + +QNetworkRequest Request::networkRequest() const +{ + QNetworkRequest request(QUrl(this->mUrl)); + + if ( !userName().isEmpty() && !password().isEmpty() ) + request.setRawHeader("Authorization", this->basicAuthorization().toUtf8()); + + if ( !token().isEmpty() ) { + request.setRawHeader("Authorization", this->bearerAuthorization().toUtf8()); + } + + // Enabled compression +#ifdef CORESDK_ZLIB + request.setRawHeader("Accept-Encoding", "gzip, deflate"); +#endif + + // Enabling HTTP/2 ( not supported on Ubuntu 16.04 ) + // request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); + return request; +} + + +void Request::appendData(const QByteArray &array) +{ + mResponseData += array; +} + +QByteArray Request::responseData() const +{ + return mResponseData; +} + +QByteArray Request::requestData() const +{ + return mRequestData; +} + +void Request::setRequestData(const QByteArray &requestData) +{ + mRequestData = requestData; +} + +QString Request::token() const +{ + return mToken; +} + +void Request::setToken(const QString &token) +{ + mToken = token; +} + +QString Request::userName() const +{ + return mUserName; +} + +void Request::setUserName(const QString &username) +{ + mUserName = username; +} + +QString Request::password() const +{ + return mPassword; +} + +void Request::setPassword(const QString &password) +{ + mPassword = password; +} + +QString Request::basicAuthorization() const +{ + // HTTP Basic authentication header value: base64(username:password) + QString concatenated = userName() + ":" + password(); + QByteArray data = concatenated.toLocal8Bit().toBase64(); + QString headerData = "Basic " + data; + return headerData; + //request.setRawHeader("Authorization", headerData.toLocal8Bit()); +} + +QString Request::bearerAuthorization() const +{ + qCDebug(sdknetwork) << "not implemented yet"; + return QString(); +} + +} // core diff --git a/src/core/request.h b/src/core/request.h new file mode 100644 index 0000000..cfbe617 --- /dev/null +++ b/src/core/request.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +namespace core { + +class Request : public QObject { + Q_OBJECT + friend class RequestManager; + friend class RequestTest; +public: + Request() = default; + ~Request() override; + Request(QString type, QString url, QByteArray responseData = QByteArray()); + QNetworkRequest networkRequest() const; + + // Data handling data + QByteArray requestData() const; + void setRequestData(const QByteArray &requestData); + QByteArray responseData() const; + + + // Authorization + QString userName() const; + void setUserName(const QString &userName); + QString password() const; + void setPassword(const QString &password); + QString token() const; + void setToken(const QString &token); + + // Authorization headers + QString basicAuthorization() const; + QString bearerAuthorization() const; + +private: + // Data handling + void appendData(const QByteArray &array); + + +signals: + void finished(); + +private: + QString mType; // POST, GET + QString mUrl; + + // Authorization + QString mUserName; + QString mPassword; + QString mToken; + + // Data + QByteArray mRequestData; + QByteArray mResponseData; +}; + +} // core diff --git a/src/core/requestmanager.cpp b/src/core/requestmanager.cpp new file mode 100644 index 0000000..775b09a --- /dev/null +++ b/src/core/requestmanager.cpp @@ -0,0 +1,95 @@ +#include "requestmanager.h" +#include "request.h" + +#ifdef CORESDK_ZLIB +#include "compression.h" +#endif + +#include + +namespace core { + +/** + * @brief Wrapper around QNetworkAccessManger to handle soap protocol + * @param parent + */ +RequestManager::RequestManager(QObject *parent) + : QObject(parent) +{ + connect(&mNetworkAccessManager, &QNetworkAccessManager::authenticationRequired, [](){ + qCWarning(sdknetwork) << "server need authentication"; + }); +} + + +/** + * @brief Soap::downloadRequest + * @param soapRequest + */ +void RequestManager::downloadRequest(const std::shared_ptr& request) +{ + QNetworkReply *reply = mNetworkAccessManager.post(request->networkRequest(), request->requestData()); + mRequestMap.insert(reply, request); + + connect(reply, &QNetworkReply::sslErrors, this, &RequestManager::sslErrors); + connect(reply, &QNetworkReply::downloadProgress, this, &RequestManager::downloadProgress); + + connect(reply, &QNetworkReply::finished, this, [=]() { + std::shared_ptr request = mRequestMap.value(reply); + mRequestMap.remove(reply); + reply->deleteLater(); + emit request->finished(); + emit downloadFinished(request); + }); +} + +/** + * @brief Handle sslErrors -> only debug output + * @param sslErrors ( from QNetworkReply::sslErrors ) + */ +void RequestManager::sslErrors(const QList &sslErrors) +{ + for (const QSslError &error : sslErrors) { + qCDebug(sdknetwork) << QStringLiteral("SSL error:") << error.errorString(); + } +} + +/** + * @brief called upon download progess -> adding data into QByteArray + * @param bytesReceived ( can be different from actual data -> compression ) + * @param bytesTotal ( can be different from actual data -> compression ) + */ +void RequestManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + // Get Reply ( now only one ) + //Q_ASSERT(mCurrentReply); + auto *reply = qobject_cast(sender()); + Q_ASSERT(mRequestMap.contains(reply)); + std::shared_ptr request = mRequestMap.value(reply); + //Q_ASSERT(reply == mCurrentReply); + + QString encoding; + + // Check encoding + for (const auto & pair : reply->rawHeaderPairs()) { + if (pair.first == QStringLiteral("Content-Encoding")) { + encoding = pair.second; + } + } + + QByteArray data = reply->readAll(); + + // Decompress gzip data +#ifdef CORESDK_ZLIB + if (encoding.toLower() == "gzip" && !data.isEmpty() ) { + data = Compression::decompress(data); + } +#endif + + // Append data to request + request->appendData(data); + + emit progresss(bytesReceived, bytesTotal); +} + +} // core diff --git a/src/core/requestmanager.h b/src/core/requestmanager.h new file mode 100644 index 0000000..0d0add3 --- /dev/null +++ b/src/core/requestmanager.h @@ -0,0 +1,42 @@ +#pragma once + +#include "logger.h" +#include "request.h" + +#include + +#include + +namespace core { + +/** + * @brief Will download only ONE ITEM at a time + */ +class RequestManager : public QObject +{ + Q_OBJECT; + friend class SoapTest; +public: + explicit RequestManager(QObject *parent = nullptr); + + void downloadRequest(const std::shared_ptr& request); + + // QByteArray data() const; + +private: + Q_SLOT void sslErrors(const QList &sslErrors); + Q_SLOT void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + + +signals: + void downloadFinished(std::shared_ptr request); + void progresss(qint64 bytesReceived, qint64 bytesTotal); + +private: + QNetworkAccessManager mNetworkAccessManager; + //QNetworkReply *mCurrentReply = nullptr; +// QByteArray mData; + QMap> mRequestMap; +}; + +} // core diff --git a/src/core/zlib.pri b/src/core/zlib.pri new file mode 100644 index 0000000..f2ccc7c --- /dev/null +++ b/src/core/zlib.pri @@ -0,0 +1,8 @@ +INCLUDEPATH += $$PWD + + +SOURCES += \ + $$PWD/compression.cpp \ + +HEADERS += \ + $$PWD/compression.h \ diff --git a/src/lib/lib.pro b/src/lib/lib.pro new file mode 100644 index 0000000..34e1b7e --- /dev/null +++ b/src/lib/lib.pro @@ -0,0 +1,5 @@ +TEMPLATE = lib + +QT += core sql network + +include(../core/core.pri) diff --git a/src/testapp/app.pro b/src/testapp/app.pro new file mode 100644 index 0000000..099fd82 --- /dev/null +++ b/src/testapp/app.pro @@ -0,0 +1,6 @@ +TEMPLATE = lib + +QT += core sql network +CONFIG += debug console + +include(../core/core.pri) diff --git a/src/testapp/main.cpp b/src/testapp/main.cpp new file mode 100644 index 0000000..a94e5a0 --- /dev/null +++ b/src/testapp/main.cpp @@ -0,0 +1,20 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName("colnod-connector"); + QCoreApplication::setApplicationVersion("1.0"); + + // Command line parsing + QCommandLineParser parser; + + parser.setApplicationDescription("Colnod sync"); + QCommandLineOption dryModeOption("dryMode", "ColnodAPI", "Read-only mode, prints changes which would normally be made"); + parser.addOption(dryModeOption); + parser.process(app); + + // Synchronizaiton + return QCoreApplication::exec(); +} diff --git a/src/testapp/testapp.pro b/src/testapp/testapp.pro new file mode 100644 index 0000000..cc10148 --- /dev/null +++ b/src/testapp/testapp.pro @@ -0,0 +1,7 @@ +TEMPLATE = app + +QT += core sql network + +SOURCES += main.cpp + +include(../core/core.pri) diff --git a/test/test.pro b/test/test.pro new file mode 100644 index 0000000..42c75e8 --- /dev/null +++ b/test/test.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + unittests + diff --git a/test/unittests/tst_request.cpp b/test/unittests/tst_request.cpp new file mode 100644 index 0000000..1b1cb14 --- /dev/null +++ b/test/unittests/tst_request.cpp @@ -0,0 +1,19 @@ +#include "tst_request.h" + +#include "request.h" + +namespace core { + +void RequestTest::auth_test() +{ + QString expected = "Basic VGVzdGVyOlRlc3Q="; + Request req; + req.setUserName("Tester"); + req.setPassword("Test"); + + QCOMPARE(req.basicAuthorization(), expected); +} + +} + +QTEST_MAIN(core::RequestTest) diff --git a/test/unittests/tst_request.h b/test/unittests/tst_request.h new file mode 100644 index 0000000..af4d1f1 --- /dev/null +++ b/test/unittests/tst_request.h @@ -0,0 +1,21 @@ + +#pragma once + +#include + +namespace core { + +class RequestTest : public QObject +{ + Q_OBJECT +private: + // Default testcases ( not needed to declare it ) + // Q_SLOT void initTestCase(); + // Q_SLOT void cleanupTestCase(); + // void wont_run(); // no Q_SLOT ( only slots will be runned within tests ) + + + Q_SLOT void auth_test(); +}; + +} // diff --git a/test/unittests/unittests.pro b/test/unittests/unittests.pro new file mode 100644 index 0000000..82c1469 --- /dev/null +++ b/test/unittests/unittests.pro @@ -0,0 +1,14 @@ +QT += core sql network testlib +CONFIG += testcase # neccesary to have posibility to run: make check UnitTest + +SOURCES += \ + tst_request.cpp +HEADERS += \ + tst_request.h + +include(../../src/core/core.pri) + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target