diff --git a/libssu/ssuvariables.cpp b/libssu/ssuvariables.cpp index 7d38937..6d31fa3 100644 --- a/libssu/ssuvariables.cpp +++ b/libssu/ssuvariables.cpp @@ -6,11 +6,11 @@ */ #include +#include +#include #include "ssuvariables.h" -// TODO: Add a simple variable parser to allow variable substitution; it should -// get called in the resolve sections SsuVariables::SsuVariables(): QObject() { } @@ -25,3 +25,80 @@ void SsuVariables::resolveSection(QSettings *settings, QString section, QHashendGroup(); } + +QString SsuVariables::resolveString(QString pattern, QHash *variables){ + QRegExp regex("%\\\([^%]*\\\)", Qt::CaseSensitive, QRegExp::RegExp2); + regex.setMinimal(true); + + int pos = 0; + while ((pos = regex.indexIn(pattern, pos)) != -1){ + QString match = regex.cap(0); + + if (match.contains(":")){ + // variable is special, resolve before replacing + QString variable = resolveVariable(match, variables); + pattern.replace(match, variable); + pos += variable.length(); + } else { + // look up variable name in hashmap, and replace it with stored value, + // if found, or "" + QString variableName = match; + variableName.remove(0,2); + variableName.chop(1); + if (variables->contains(variableName)){ + pattern.replace(match, variables->value(variableName)); + pos += variables->value(variableName).length(); + } else + pattern.replace(match, ""); + } + } + + // check if string still contains variables, and recurse + if (regex.indexIn(pattern, 0) != -1) + pattern = resolveString(pattern, variables); + + return pattern; +} + +QString SsuVariables::resolveVariable(QString variable, QHash *variables){ + QString variableValue = ""; + + if (variable.endsWith(")")) + variable.chop(1); + if (variable.startsWith("%(")) + variable.remove(0,2); + + // hunt for your colon + int magic = variable.indexOf(":"); + + // seems you misplaced your colon + if (magic == -1) return variable; + + QStringRef variableName(&variable, 0, magic); + QStringRef variableSub(&variable, magic + 2, variable.length() - magic - 2); + + // Fill in variable value for later tests, if it exists + if (variables->contains(variableName.toString())) + variableValue = variables->value(variableName.toString()); + + // find the operator who's after your colon + QChar op; + if (variable.length() >= magic +1) + op = variable.at(magic + 1); + + switch(op.toAscii()){ + case '-': + // substitute default value if variable is empty + if (variableValue == "") + return variableSub.toString(); + break; + case '+': + // substitute default value if variable is not empty + if (variableValue != "") + return variableSub.toString(); + break; + } + + // no proper substitution found -> return default value + return variableValue; +} diff --git a/libssu/ssuvariables.h b/libssu/ssuvariables.h index 5e4b7ca..b3c6243 100644 --- a/libssu/ssuvariables.h +++ b/libssu/ssuvariables.h @@ -23,6 +23,14 @@ class SsuVariables: public QObject { * QHash */ void resolveSection(QSettings *settings, QString section, QHash *storageHash); + /** + * Resolve a whole string, containing several variables. Variables inside variables are allowed + */ + QString resolveString(QString pattern, QHash *variables); + /** + * Resolve variables; variable can be passed as %(var) or var + */ + QString resolveVariable(QString variable, QHash *variables); }; #endif diff --git a/tests/tests.pro b/tests/tests.pro index 7441cb8..47986fa 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += qt ordered coverage debug -SUBDIRS = ut_urlresolver +SUBDIRS = ut_urlresolver ut_variables !include( tests.pri ) { error("Unable to find tests include") } diff --git a/tests/tests.xml b/tests/tests.xml index 34fed57..3a61f90 100644 --- a/tests/tests.xml +++ b/tests/tests.xml @@ -8,5 +8,10 @@ /opt/tests/ssu/ut_urlresolver + + + /opt/tests/ssu/ut_variables + + diff --git a/tests/ut_variables/main.cpp b/tests/ut_variables/main.cpp new file mode 100644 index 0000000..73e0fbf --- /dev/null +++ b/tests/ut_variables/main.cpp @@ -0,0 +1,19 @@ +/** + * @file main.cpp + * @copyright 2012 Jolla Ltd. + * @author Bernd Wachter + * @date 2012 + */ + +#include + +#include "variablestest.h" + +int main(int argc, char **argv){ + VariablesTest variablesTest; + + if (QTest::qExec(&variablesTest, argc, argv)) + return 1; + + return 0; +} diff --git a/tests/ut_variables/ut_variables.pro b/tests/ut_variables/ut_variables.pro new file mode 100644 index 0000000..7779da7 --- /dev/null +++ b/tests/ut_variables/ut_variables.pro @@ -0,0 +1,17 @@ +HEADERS = variablestest.h +SOURCES = main.cpp \ + variablestest.cpp +TEMPLATE = app +TARGET = ut_variables +LIBS += -lssu +CONFIG -= app_bundle +CONFIG += console qtestlib +QT -= gui +QT += network testlib + +!include( ../tests.pri ) { error("Unable to find tests include") } + +unix:target.path = $${PREFIX}/$$TESTS_PATH +INSTALLS += target + +!include( ../../buildpath.pri ) { error("Unable to find build path specification") } diff --git a/tests/ut_variables/variablestest.cpp b/tests/ut_variables/variablestest.cpp new file mode 100644 index 0000000..adc826b --- /dev/null +++ b/tests/ut_variables/variablestest.cpp @@ -0,0 +1,63 @@ +/** + * @file variablestest.cpp + * @copyright 2013 Jolla Ltd. + * @author Bernd Wachter + * @date 2013 + */ + +#include "variablestest.h" + +void VariablesTest::initTestCase(){ + variables.insert("packagesDomain", "packages.example.com"); + variables.insert("releaseDomain", "releases.example.com"); + variables.insert("rndProtocol", "https"); + variables.insert("release", "devel"); + variables.insert("arch", "armv8"); + variables.insert("flavourName", "flavour"); + + urls.insert("http://%(packagesDomain)/releases/%(release)/jolla/%(arch)/", + "http://packages.example.com/releases/devel/jolla/armv8/"); + urls.insert("%(rndProtocol)://%(releaseDomain)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https://releases.example.com/nemo/devel-flavour/platform/armv8/"); + // test missing operator, which should fall back to just variable value + urls.insert("%(rndProtocol)://%(unsetDomain:)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https:///nemo/devel-flavour/platform/armv8/"); + urls.insert("%(rndProtocol)://%(releaseDomain:)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https://releases.example.com/nemo/devel-flavour/platform/armv8/"); + urls.insert("%(rndProtocol)://%(releaseDomain:unset.example.com)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https://releases.example.com/nemo/devel-flavour/platform/armv8/"); + // check if :- works + urls.insert("%(rndProtocol)://%(releaseDomain:-unset.example.com)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https://releases.example.com/nemo/devel-flavour/platform/armv8/"); + urls.insert("%(rndProtocol)://%(unsetDomain:-unset.example.com)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https://unset.example.com/nemo/devel-flavour/platform/armv8/"); + // test with empty replacement pattern + urls.insert("%(rndProtocol)://%(unsetDomain:-)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https:///nemo/devel-flavour/platform/armv8/"); + // check if :+ works + // substitution of variable with set.example.com + urls.insert("%(rndProtocol)://%(releaseDomain:+set.example.com)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https://set.example.com/nemo/devel-flavour/platform/armv8/"); + // substitution of variable with variable + /set + urls.insert("%(rndProtocol)://%(releaseDomain:+%(releaseDomain)/set)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https://releases.example.com/set/nemo/devel-flavour/platform/armv8/"); + // substitution of variable with empty variable + /set -- should substitute to "" + urls.insert("%(rndProtocol)://%(unsetDomain:+%(unsetDomain)/set)/nemo/%(release)-%(flavourName)/platform/%(arch)/", + "https:///nemo/devel-flavour/platform/armv8/"); + +} + +void VariablesTest::cleanupTestCase(){ + +} + +void VariablesTest::checkResolveString(){ + QHashIterator i(urls); + + while (i.hasNext()){ + i.next(); + QString result = var.resolveString(i.key(), &variables); + qDebug() << i.key() << " resolved to " << result; + QCOMPARE(result, i.value()); + } +} diff --git a/tests/ut_variables/variablestest.h b/tests/ut_variables/variablestest.h new file mode 100644 index 0000000..4ece17d --- /dev/null +++ b/tests/ut_variables/variablestest.h @@ -0,0 +1,33 @@ +/** + * @file variablestest.h + * @copyright 2013 Jolla Ltd. + * @author Bernd Wachter + * @date 2013 + */ + +#ifndef _VARIABLESTEST_H +#define _VARIABLESTEST_H + +#include +#include +#include + +#include +#include + +class VariablesTest: public QObject { + Q_OBJECT + + private slots: + void initTestCase(); + void cleanupTestCase(); + void checkResolveString(); + + + private: + Ssu ssu; + SsuVariables var; + QHash variables, urls; +}; + +#endif