Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
Also extracts parseCommand() to a separate file for simpler testing
setup.
  • Loading branch information
Chih-Hsuan Yen committed Aug 29, 2022
1 parent c3fe003 commit 68a44df
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 43 deletions.
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ include(GNUInstallDirs)
set(QTERMINAL_VERSION "1.1.0")

option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF)
option(BUILD_TESTS "Builds tests" ON)

if(APPLE)
option(APPLEBUNDLE "Build as qterminal.app bundle" ON)
Expand All @@ -36,6 +37,10 @@ endif()
find_package(QTermWidget5 ${QTERMWIDGET_MINIMUM_VERSION} REQUIRED)
find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED)

if (BUILD_TESTS)
find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Test)
endif()

include(LXQtPreventInSourceBuilds)
include(LXQtTranslateTs)
include(LXQtTranslateDesktop)
Expand Down Expand Up @@ -75,6 +80,7 @@ set(QTERM_SRC
src/fontdialog.cpp
src/dbusaddressable.cpp
src/tab-switcher.cpp
src/qterminalutils.cpp
)

set(QTERM_MOC_SRC
Expand Down Expand Up @@ -265,3 +271,8 @@ else()
COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.app/Contents/Resources/empty.lproj"
COMMENT "Creating Resources/empty.lproj")
endif()

if(BUILD_TESTS)
enable_testing()
add_subdirectory(test)
endif()
44 changes: 1 addition & 43 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include "mainwindow.h"
#include "qterminalapp.h"
#include "qterminalutils.h"
#include "terminalconfig.h"

#define out
Expand Down Expand Up @@ -72,49 +73,6 @@ QTerminalApp * QTerminalApp::m_instance = nullptr;
exit(code);
}

QStringList parse_command(const QString& str)
{
const QRegularExpression separator(QString::fromLatin1(R"('|(?<!\\)(\\{2})*(\s|")|\z)"));
const QRegularExpression doubleQuote(QString::fromLatin1(R"((?<!\\)(\\{2})*")"));
const QRegularExpression escapedSpace(QString::fromLatin1(R"(\\(\\{2})*\s)"));
const QRegularExpression singleQuote(QStringLiteral("'"));

QStringList list;
QRegularExpressionMatch match;
int index = 0;
int nextIndex;
while((nextIndex = str.indexOf(separator, index, &match)) != -1)
{
if (nextIndex > index)
{
list << str.mid(index, nextIndex - index).replace(escapedSpace, QStringLiteral(" "));
}
if (match.capturedLength() == 0)
{ // end of string ("\z") is matched
break;
}
index = nextIndex + match.capturedLength();
auto c = str.at(index - 1); // last matched character
if (!c.isSpace())
{ // a single quote or an unescaped double quote is matched
nextIndex = str.indexOf(c == QLatin1Char('\'') ? singleQuote : doubleQuote, index, &match);
if (nextIndex == -1)
{ // the quote is not closed
break;
}
else
{
if (nextIndex > index)
{
list << str.mid(index, nextIndex - index).replace(escapedSpace, QStringLiteral(" "));
}
index = nextIndex + match.capturedLength();
}
}
}
return list;
}

void parse_args(int argc, char* argv[], QString& workdir, QStringList & shell_command, out bool& dropMode)
{
int next_option;
Expand Down
64 changes: 64 additions & 0 deletions src/qterminalutils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/***************************************************************************
* Copyright (C) 2022 by LXQt team *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/

#include <QRegularExpression>

#include "qterminalutils.h"

QStringList parse_command(const QString& str)
{
const QRegularExpression separator(QString::fromLatin1(R"('|(?<!\\)(\\{2})*(\s|")|\z)"));
const QRegularExpression doubleQuote(QString::fromLatin1(R"((?<!\\)(\\{2})*")"));
const QRegularExpression escapedSpace(QString::fromLatin1(R"(\\(\\{2})*\s)"));
const QRegularExpression singleQuote(QStringLiteral("'"));

QStringList list;
QRegularExpressionMatch match;
int index = 0;
int nextIndex;
while((nextIndex = str.indexOf(separator, index, &match)) != -1)
{
if (nextIndex > index)
{
list << str.mid(index, nextIndex - index).replace(escapedSpace, QStringLiteral(" "));
}
if (match.capturedLength() == 0)
{ // end of string ("\z") is matched
break;
}
index = nextIndex + match.capturedLength();
auto c = str.at(index - 1); // last matched character
if (!c.isSpace())
{ // a single quote or an unescaped double quote is matched
nextIndex = str.indexOf(c == QLatin1Char('\'') ? singleQuote : doubleQuote, index, &match);
if (nextIndex == -1)
{ // the quote is not closed
break;
}
else
{
if (nextIndex > index)
{
list << str.mid(index, nextIndex - index).replace(escapedSpace, QStringLiteral(" "));
}
index = nextIndex + match.capturedLength();
}
}
}
return list;
}

26 changes: 26 additions & 0 deletions src/qterminalutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/***************************************************************************
* Copyright (C) 2022 by LXQt team *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/

#ifndef QTERMINALUTILS_H
#define QTERMINALUTILS_H

#include <QString>
#include <QStringList>

QStringList parse_command(const QString& str);

#endif
7 changes: 7 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
qt5_wrap_cpp(QTERM_TEST_MOC qterminal_test.h)
add_executable(qterminal_test
qterminal_test.cpp
${CMAKE_SOURCE_DIR}/src/qterminalutils.cpp
${QTERM_TEST_MOC})
target_link_libraries(qterminal_test Qt5::Test)
add_test(NAME qterminal_test COMMAND qterminal_test)
53 changes: 53 additions & 0 deletions test/qterminal_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/***************************************************************************
* Copyright (C) 2022 by LXQt team *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/

#include "qterminal_test.h"

#include "qterminalutils.h"

#include <QtTest>

// handy shortcut copied from liblxqt
#ifndef QL1S
#define QL1S(x) QLatin1String(x)
#endif

void QTerminalTest::testParseCommand()
{
/* Common usage */
// qterminal -e 'fpad -s "PATH/ha ha"'
// qterminal -e "fpad -s \"PATH/ha ha\"" # \" is decoded as " by the shell
QCOMPARE(parse_command(QL1S(R"(fpad -s "PATH/ha ha")")),
QStringList() << QL1S("fpad") << QL1S("-s") << QL1S("PATH/ha ha"));
// qterminal -e "fpad -s 'PATH/ha ha'"
QCOMPARE(parse_command(QL1S(R"(fpad -s 'PATH/ha ha')")),
QStringList() << QL1S("fpad") << QL1S("-s") << QL1S("PATH/ha ha"));
// qterminal -e 'fpad -s PATH/ha\ ha'
// qterminal -e "fpad -s PATH/ha\ ha"
QCOMPARE(parse_command(QL1S(R"(fpad -s PATH/ha\ ha)")),
QStringList() << QL1S("fpad") << QL1S("-s") << QL1S("PATH/ha ha"));

/* Uncommon usage */
// qterminal -e 'fpad -s \"PATH/ha ha\"'
QCOMPARE(parse_command(QL1S(R"(fpad -s \"PATH/ha ha\")")),
QStringList() << QL1S("fpad") << QL1S("-s") << QL1S("\\\"PATH/ha") << QL1S("ha\\\""));
// qterminal -e 'fpad -s "PATH/ha\ ha"'
QCOMPARE(parse_command(QL1S(R"(fpad -s "PATH/ha\ ha")")),
QStringList() << QL1S("fpad") << QL1S("-s") << QL1S("PATH/ha ha"));
}

QTEST_MAIN(QTerminalTest)
32 changes: 32 additions & 0 deletions test/qterminal_test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/***************************************************************************
* Copyright (C) 2022 by LXQt team *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/

#ifndef QTERMINAL_TEST_H
#define QTERMINAL_TEST_H

#include <QObject>

class QTerminalTest : public QObject
{
Q_OBJECT

// Each private slot is a test function
private Q_SLOTS:
void testParseCommand();
};

#endif

0 comments on commit 68a44df

Please sign in to comment.