Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
find_package(Qt6Test ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
|
||||
set_package_properties(Qt6Test PROPERTIES PURPOSE "Required for tests")
|
||||
|
||||
remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_KEYWORDS)
|
||||
|
||||
include(ECMMarkAsTest)
|
||||
include(ECMAddTests)
|
||||
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
ecm_add_tests(
|
||||
fallbackpackagetest.cpp
|
||||
packagestructuretest.cpp
|
||||
plasmoidpackagetest.cpp
|
||||
querytest.cpp
|
||||
LINK_LIBRARIES Qt6::Test KF6::Package KF6::I18n KF6::Archive
|
||||
)
|
||||
|
||||
|
||||
kcoreaddons_add_plugin(plasmoidstructure_plugin STATIC SOURCES packagestructures/plasmoidstructure.cpp INSTALL_NAMESPACE kf6/packagestructure)
|
||||
target_link_libraries(plasmoidstructure_plugin KF6::Package)
|
||||
kcoreaddons_target_static_plugins(querytest NAMESPACE kf6/packagestructure)
|
||||
kcoreaddons_target_static_plugins(plasmoidpackagetest NAMESPACE kf6/packagestructure)
|
||||
|
||||
set_tests_properties(querytest PROPERTIES RUN_SERIAL TRUE) # it wipes out ~/.qttest/share
|
||||
set_tests_properties(plasmoidpackagetest PROPERTIES RUN_SERIAL TRUE)
|
||||
|
||||
function(kpackagetooltest testname)
|
||||
add_test(NAME ${testname}-appstream COMMAND cmake -Dkpackagetool=$<TARGET_FILE:kpackagetool6>
|
||||
-Dgenerated=${CMAKE_CURRENT_BINARY_DIR}/${testname}.appdata.xml
|
||||
-Dinput=${CMAKE_CURRENT_LIST_DIR}/data/${testname}/
|
||||
-Doutput=${CMAKE_CURRENT_SOURCE_DIR}/data/${testname}/${testname}.testappdataxml
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/kpackagetoolappstreamtest.cmake
|
||||
)
|
||||
set(XDG_DATA_DIRS "$ENV{XDG_DATA_DIRS}")
|
||||
if(NOT XDG_DATA_DIRS)
|
||||
set(XDG_DATA_DIRS "/usr/local/share:/usr/share")
|
||||
endif()
|
||||
set_property(TEST ${testname}-appstream PROPERTY ENVIRONMENT "XDG_DATA_DIRS=${CMAKE_SOURCE_DIR}/src/kpackage/data:${XDG_DATA_DIRS}")
|
||||
endfunction()
|
||||
|
||||
foreach(var "testfallbackpackage" "testpackage" "testpackage-nodisplay" "testpackagesdep" "testpackagesdepinvalid") # "customcontent" "simplecontent"
|
||||
kpackagetooltest(${var})
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(mockdepresolver)
|
||||
@@ -0,0 +1 @@
|
||||
#define KPACKAGE_DEP_RESOLVERS "${CMAKE_BINARY_DIR}/bin"
|
||||
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Id": "org.kde.customcontent",
|
||||
"Name": "Custom Content"
|
||||
},
|
||||
"KPackageStructure": "KPackage/CustomContent"
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Id": "org.kde.simplecontent",
|
||||
"Name": "Simple Content"
|
||||
},
|
||||
"KPackageStructure": "KPackage/SimpleContent"
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Description": "test description",
|
||||
"Id": "org.kde.testfallbackpackage",
|
||||
"License": "GPLv2+",
|
||||
"Name": "Test Fallback Package"
|
||||
},
|
||||
"KPackageStructure": "Plasma/TestKPackageInternalPlasmoid"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component>
|
||||
<id>org.kde.testfallbackpackage</id>
|
||||
<name>Test Fallback Package</name>
|
||||
<summary>test description</summary>
|
||||
<url type="donation">https://www.kde.org/donate.php?app=org.kde.testfallbackpackage</url>
|
||||
<developer_name>Marco Martin <mart@kde.org></developer_name>
|
||||
<project_license>GPL-2.0+</project_license>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
</component>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "bshah@kde
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Description": "fancy shmancy summary",
|
||||
"Icon": "plasma",
|
||||
"Id": "org.kde.testpackage",
|
||||
"License": "GPLv2+",
|
||||
"Name": "Test Package"
|
||||
},
|
||||
"KPackageStructure": "KPackage/Generic",
|
||||
"NoDisplay": true
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
88a45736f27b7b477a470feaacd9e725232c47cc
|
||||
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "darkblue"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "jblow@kde.org",
|
||||
"Name": "Joe Blow"
|
||||
}
|
||||
],
|
||||
"Category": "",
|
||||
"Description": "fancy shmancy summary",
|
||||
"Icon": "plasma",
|
||||
"Id": "org.kde.testpackage",
|
||||
"License": "GPLv2+",
|
||||
"Website": "https://kde.org",
|
||||
"Name": "Test Package",
|
||||
"Name[ar]": "حزمة اختبارية",
|
||||
"Name[ast]": "Paquete de prueba",
|
||||
"Name[bs]": "Testni paket",
|
||||
"Name[ca@valencia]": "Paquet de proves",
|
||||
"Name[ca]": "Paquet de proves",
|
||||
"Name[cs]": "Testovací balíček",
|
||||
"Name[da]": "Testpakke",
|
||||
"Name[de]": "Test-Paket",
|
||||
"Name[el]": "Πακέτο δοκιμής",
|
||||
"Name[en_GB]": "Test Package",
|
||||
"Name[es]": "Probar el paquete",
|
||||
"Name[fi]": "Testipaketti",
|
||||
"Name[fr]": "Paquet de test",
|
||||
"Name[gd]": "Pacaid dheuchainneach",
|
||||
"Name[gl]": "Paquete de probas",
|
||||
"Name[hu]": "Tesztcsomag",
|
||||
"Name[ia]": "Pacchetto de prova",
|
||||
"Name[it]": "Pacchetto di prova",
|
||||
"Name[ko]": "테스트 패키지",
|
||||
"Name[mr]": "चाचणी पॅकेज",
|
||||
"Name[nb]": "Test pakke",
|
||||
"Name[nds]": "Testpaket",
|
||||
"Name[nl]": "Testpakket",
|
||||
"Name[nn]": "Test pakke",
|
||||
"Name[pa]": "ਟੈਸਟ ਪੈਕੇਜ",
|
||||
"Name[pl]": "Pakiet próbny",
|
||||
"Name[pt]": "Pacote de Teste",
|
||||
"Name[pt_BR]": "Pacote de teste",
|
||||
"Name[ro]": "Pachet de test",
|
||||
"Name[ru]": "Тестовый пакет",
|
||||
"Name[sk]": "Testovací balík",
|
||||
"Name[sl]": "Preizkusni paket",
|
||||
"Name[sr@ijekavian]": "Пробни пакет",
|
||||
"Name[sr@ijekavianlatin]": "Probni paket",
|
||||
"Name[sr@latin]": "Probni paket",
|
||||
"Name[sr]": "Пробни пакет",
|
||||
"Name[sv]": "Testpaket",
|
||||
"Name[tr]": "Paketi Denetle",
|
||||
"Name[uk]": "Тестовий пакунок",
|
||||
"Name[x-test]": "xxTest Packagexx",
|
||||
"Name[zh_CN]": "测试包",
|
||||
"Name[zh_TW]": "測試套件"
|
||||
},
|
||||
"KPackageStructure": "Plasma/TestKPackageInternalPlasmoid"
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component>
|
||||
<id>org.kde.testpackage</id>
|
||||
<name>Test Package</name>
|
||||
<name xml:lang="ar">حزمة اختبارية</name>
|
||||
<name xml:lang="ast">Paquete de prueba</name>
|
||||
<name xml:lang="bs">Testni paket</name>
|
||||
<name xml:lang="ca@valencia">Paquet de proves</name>
|
||||
<name xml:lang="ca">Paquet de proves</name>
|
||||
<name xml:lang="cs">Testovací balíček</name>
|
||||
<name xml:lang="da">Testpakke</name>
|
||||
<name xml:lang="de">Test-Paket</name>
|
||||
<name xml:lang="el">Πακέτο δοκιμής</name>
|
||||
<name xml:lang="en_GB">Test Package</name>
|
||||
<name xml:lang="es">Probar el paquete</name>
|
||||
<name xml:lang="fi">Testipaketti</name>
|
||||
<name xml:lang="fr">Paquet de test</name>
|
||||
<name xml:lang="gd">Pacaid dheuchainneach</name>
|
||||
<name xml:lang="gl">Paquete de probas</name>
|
||||
<name xml:lang="hu">Tesztcsomag</name>
|
||||
<name xml:lang="ia">Pacchetto de prova</name>
|
||||
<name xml:lang="it">Pacchetto di prova</name>
|
||||
<name xml:lang="ko">테스트 패키지</name>
|
||||
<name xml:lang="mr">चाचणी पॅकेज</name>
|
||||
<name xml:lang="nb">Test pakke</name>
|
||||
<name xml:lang="nds">Testpaket</name>
|
||||
<name xml:lang="nl">Testpakket</name>
|
||||
<name xml:lang="nn">Test pakke</name>
|
||||
<name xml:lang="pa">ਟੈਸਟ ਪੈਕੇਜ</name>
|
||||
<name xml:lang="pl">Pakiet próbny</name>
|
||||
<name xml:lang="pt">Pacote de Teste</name>
|
||||
<name xml:lang="pt_BR">Pacote de teste</name>
|
||||
<name xml:lang="ro">Pachet de test</name>
|
||||
<name xml:lang="ru">Тестовый пакет</name>
|
||||
<name xml:lang="sk">Testovací balík</name>
|
||||
<name xml:lang="sl">Preizkusni paket</name>
|
||||
<name xml:lang="sr@ijekavian">Пробни пакет</name>
|
||||
<name xml:lang="sr@ijekavianlatin">Probni paket</name>
|
||||
<name xml:lang="sr@latin">Probni paket</name>
|
||||
<name xml:lang="sr">Пробни пакет</name>
|
||||
<name xml:lang="sv">Testpaket</name>
|
||||
<name xml:lang="tr">Paketi Denetle</name>
|
||||
<name xml:lang="uk">Тестовий пакунок</name>
|
||||
<name xml:lang="x-test">xxTest Packagexx</name>
|
||||
<name xml:lang="zh_CN">测试包</name>
|
||||
<name xml:lang="zh_TW">測試套件</name>
|
||||
<summary>fancy shmancy summary</summary>
|
||||
<url type="donation">https://www.kde.org/donate.php?app=org.kde.testpackage</url>
|
||||
<developer_name>Joe Blow <jblow@kde.org></developer_name>
|
||||
<icon type="stock">plasma</icon>
|
||||
<project_license>GPL-2.0+</project_license>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
</component>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Id": "org.kde.testpackagesdep",
|
||||
"License": "GPLv2+",
|
||||
"Name": "Test Packages with Dependencies",
|
||||
"Description": "test description"
|
||||
},
|
||||
"KPackageStructure": "Plasma/TestKPackageInternalPlasmoid",
|
||||
"X-KPackage-Dependencies": [
|
||||
"mock://validdep",
|
||||
"mock://validdep2"
|
||||
]
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component>
|
||||
<id>org.kde.testpackagesdep</id>
|
||||
<name>Test Packages with Dependencies</name>
|
||||
<summary>test description</summary>
|
||||
<url type="donation">https://www.kde.org/donate.php?app=org.kde.testpackagesdep</url>
|
||||
<developer_name>Aleix <aleixpol@kde.org></developer_name>
|
||||
<project_license>GPL-2.0+</project_license>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
</component>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
Rectangle {}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "bshah@kde.org",
|
||||
"Name": "Bhushan"
|
||||
}
|
||||
],
|
||||
"Id": "org.kde.testpackagesdepinvalid",
|
||||
"License": "GPLv2+",
|
||||
"Name": "Test Packages with Dependencies",
|
||||
"Description": "test description"
|
||||
},
|
||||
"KPackageStructure": "Plasma/TestKPackageInternalPlasmoid",
|
||||
"X-KPackage-Dependencies": [
|
||||
"mock://invaliddep"
|
||||
]
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component>
|
||||
<id>org.kde.testpackagesdepinvalid</id>
|
||||
<name>Test Packages with Dependencies</name>
|
||||
<summary>test description</summary>
|
||||
<url type="donation">https://www.kde.org/donate.php?app=org.kde.testpackagesdepinvalid</url>
|
||||
<developer_name>Bhushan <bshah@kde.org></developer_name>
|
||||
<project_license>GPL-2.0+</project_license>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
</component>
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
|
||||
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "fallbackpackagetest.h"
|
||||
|
||||
#include "packageloader.h"
|
||||
#include "packagestructure.h"
|
||||
#include <KLocalizedString>
|
||||
|
||||
void FallbackPackageTest::initTestCase()
|
||||
{
|
||||
m_fallPackagePath = QFINDTESTDATA("data/testpackage");
|
||||
m_fallbackPkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/Generic"));
|
||||
m_fallbackPkg.addFileDefinition("mainscript", QStringLiteral("ui/main.qml"));
|
||||
m_fallbackPkg.setPath(m_fallPackagePath);
|
||||
|
||||
m_packagePath = QFINDTESTDATA("data/testfallbackpackage");
|
||||
m_pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/Generic"));
|
||||
m_pkg.addFileDefinition("mainscript", QStringLiteral("ui/main.qml"));
|
||||
m_pkg.setPath(m_packagePath);
|
||||
}
|
||||
|
||||
void FallbackPackageTest::beforeFallback()
|
||||
{
|
||||
QVERIFY(m_fallbackPkg.hasValidStructure());
|
||||
QVERIFY(m_pkg.hasValidStructure());
|
||||
|
||||
// m_fallbackPkg should have otherfile.qml, m_pkg shouldn't
|
||||
QVERIFY(!m_fallbackPkg.filePath("ui", QStringLiteral("otherfile.qml")).isEmpty());
|
||||
QVERIFY(m_pkg.filePath("ui", QStringLiteral("otherfile.qml")).isEmpty());
|
||||
}
|
||||
|
||||
void FallbackPackageTest::afterFallback()
|
||||
{
|
||||
m_pkg.setFallbackPackage(m_fallbackPkg);
|
||||
|
||||
// after setting the fallback, m_pkg should resolve the exact same file as m_fallbackPkg
|
||||
// for otherfile.qml
|
||||
QVERIFY(!m_pkg.filePath("ui", QStringLiteral("otherfile.qml")).isEmpty());
|
||||
QCOMPARE(m_fallbackPkg.filePath("ui", QStringLiteral("otherfile.qml")), m_pkg.filePath("ui", QStringLiteral("otherfile.qml")));
|
||||
QVERIFY(m_fallbackPkg.filePath("mainscript") != m_pkg.filePath("mainscript"));
|
||||
}
|
||||
|
||||
void FallbackPackageTest::cycle()
|
||||
{
|
||||
m_fallbackPkg.setFallbackPackage(m_pkg);
|
||||
m_pkg.setFallbackPackage(m_fallbackPkg);
|
||||
|
||||
// The cycle should have been detected and filePath should take a not infinite time
|
||||
QTRY_COMPARE_WITH_TIMEOUT(m_fallbackPkg.filePath("ui", QStringLiteral("otherfile.qml")), m_pkg.filePath("ui", QStringLiteral("otherfile.qml")), 1000);
|
||||
}
|
||||
|
||||
QTEST_MAIN(FallbackPackageTest)
|
||||
|
||||
#include "moc_fallbackpackagetest.cpp"
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
|
||||
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef FALLBACKPACKAGETEST_H
|
||||
#define FALLBACKPACKAGETEST_H
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include "kpackage/package.h"
|
||||
|
||||
class FallbackPackageTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void beforeFallback();
|
||||
void afterFallback();
|
||||
void cycle();
|
||||
|
||||
private:
|
||||
KPackage::Package m_pkg;
|
||||
KPackage::Package m_fallbackPkg;
|
||||
QString m_packagePath;
|
||||
QString m_fallPackagePath;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
get_filename_component(generated_name ${generated} NAME)
|
||||
|
||||
if(NOT ${generated_name} STREQUAL "testpackage.appdata.xml")
|
||||
message(STATUS "cd ${input} ; ${kpackagetool} --appstream-metainfo . --appstream-metainfo-output ${generated}")
|
||||
execute_process(COMMAND ${kpackagetool} --appstream-metainfo . --appstream-metainfo-output "${generated}"
|
||||
WORKING_DIRECTORY ${input}
|
||||
ERROR_VARIABLE std_error_output)
|
||||
else()
|
||||
message(STATUS "cd ${input} ; ${kpackagetool} --appstream-metainfo .")
|
||||
# Make sure that without output argument we get the output on STDOUT.
|
||||
# This only runs on the testpackage test.
|
||||
execute_process(COMMAND ${kpackagetool} --appstream-metainfo .
|
||||
WORKING_DIRECTORY ${input}
|
||||
OUTPUT_FILE "${generated}"
|
||||
ERROR_VARIABLE std_error_output)
|
||||
endif()
|
||||
|
||||
if (std_error_output)
|
||||
message(STATUS "${std_error_output}")
|
||||
endif()
|
||||
|
||||
# We'll want no generated output file at all on NoDisplay. For other tests we'll want to compare
|
||||
# the expected with the generated output.
|
||||
if(${generated_name} STREQUAL "testpackage-nodisplay.appdata.xml")
|
||||
if(EXISTS "${generated}")
|
||||
message(FATAL_ERROR "expected file ${output} does not exist, but one was generated at ${generated}")
|
||||
endif()
|
||||
else()
|
||||
execute_process(COMMAND cmake -E compare_files ${output} ${generated} ERROR_VARIABLE error_compare)
|
||||
if (error_compare)
|
||||
message(FATAL_ERROR "error on compare: ${error_compare}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Make sure the standard test passes appstream validation.
|
||||
if(${generated_name} STREQUAL "testpackage.appdata.xml")
|
||||
find_program(APPSTREAMCLI appstreamcli)
|
||||
if(APPSTREAMCLI)
|
||||
execute_process(COMMAND ${APPSTREAMCLI} validate ${generated}
|
||||
ERROR_VARIABLE appstream_stderr
|
||||
OUTPUT_VARIABLE appstream_stdout
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
if(NOT result EQUAL 0)
|
||||
message(FATAL_ERROR "appstream data seems to be imperfect: ${appstream_stderr} ${appstream_stdout}")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "skipping appstream validation as no appstreamcli binary was found")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,3 @@
|
||||
add_executable(mockhandler main.cpp)
|
||||
ecm_mark_nongui_executable(mockhandler)
|
||||
target_link_libraries(mockhandler Qt6::Core)
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Bhushan Shah <bshah@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
Q_ASSERT(app.arguments().count() == 2);
|
||||
|
||||
const QUrl url(app.arguments().constLast());
|
||||
Q_ASSERT(url.isValid());
|
||||
Q_ASSERT(url.scheme() == QLatin1String("mock"));
|
||||
|
||||
// This is very basic dep resolver used for mocking in tests
|
||||
// if asked to install invalidapp, will fail
|
||||
// if asked to install validdep, will pass
|
||||
const QString componentName = url.host();
|
||||
if (componentName.isEmpty()) {
|
||||
qWarning() << "wrongly formatted URI" << url;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (componentName == QStringLiteral("invaliddep")) {
|
||||
qWarning() << "package asked to install invalid dep, bailing out";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (componentName.startsWith(QLatin1String("validdep"))) {
|
||||
qWarning() << "asked to install valid dep, success!";
|
||||
return 0;
|
||||
}
|
||||
|
||||
qWarning() << "Assuming provided package is not available";
|
||||
return 1;
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"KPackageStructure": "Plasma/TestKPackageInternalPlasmoid"
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007-2009 Aaron Seigo <aseigo@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "packagestructure.h"
|
||||
#include <KPluginFactory>
|
||||
|
||||
class PlasmoidTestPackageStructure : public KPackage::PackageStructure
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using KPackage::PackageStructure::PackageStructure;
|
||||
|
||||
void initPackage(KPackage::Package *package) override
|
||||
{
|
||||
KPackage::PackageStructure::initPackage(package);
|
||||
package->setDefaultPackageRoot(QStringLiteral("plasma/plasmoids/"));
|
||||
|
||||
package->addDirectoryDefinition("ui", QStringLiteral("ui"));
|
||||
package->addFileDefinition("mainscript", QStringLiteral("ui/main.qml"));
|
||||
package->setRequired("mainscript", true);
|
||||
|
||||
package->addFileDefinition("configmodel", QStringLiteral("config/config.qml"));
|
||||
package->addFileDefinition("mainconfigxml", QStringLiteral("config/main.xml"));
|
||||
|
||||
package->addDirectoryDefinition("images", QStringLiteral("images"));
|
||||
package->setMimeTypes("images", {QStringLiteral("image/svg+xml"), QStringLiteral("image/png"), QStringLiteral("image/jpeg")});
|
||||
|
||||
package->addDirectoryDefinition("scripts", QStringLiteral("code"));
|
||||
package->setMimeTypes("scripts", {QStringLiteral("text/plain")});
|
||||
}
|
||||
};
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(PlasmoidTestPackageStructure, "plasmoidpackagestructure.json")
|
||||
|
||||
#include "plasmoidstructure.moc"
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
|
||||
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "packagestructuretest.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QDebug>
|
||||
|
||||
#include "packageloader.h"
|
||||
#include "packagestructure.h"
|
||||
#include "private/utils.h"
|
||||
|
||||
class NoPrefixes : public KPackage::Package
|
||||
{
|
||||
public:
|
||||
explicit NoPrefixes()
|
||||
: KPackage::Package(new KPackage::PackageStructure)
|
||||
{
|
||||
setContentsPrefixPaths(QStringList());
|
||||
addDirectoryDefinition("bin", QStringLiteral("bin"));
|
||||
addFileDefinition("MultiplePaths", QStringLiteral("first"));
|
||||
addFileDefinition("MultiplePaths", QStringLiteral("second"));
|
||||
setPath(QStringLiteral("/"));
|
||||
}
|
||||
};
|
||||
|
||||
class Wallpaper : public KPackage::PackageStructure
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
void initPackage(KPackage::Package *package) override
|
||||
{
|
||||
package->addDirectoryDefinition("images", QStringLiteral("images/"));
|
||||
|
||||
const QStringList mimetypes{QStringLiteral("image/svg"), QStringLiteral("image/png"), QStringLiteral("image/jpeg"), QStringLiteral("image/jpg")};
|
||||
package->setMimeTypes("images", mimetypes);
|
||||
|
||||
package->setRequired("images", true);
|
||||
package->addFileDefinition("screenshot", QStringLiteral("screenshot.png"));
|
||||
package->setAllowExternalPaths(true);
|
||||
}
|
||||
void pathChanged(KPackage::Package *package) override
|
||||
{
|
||||
static bool guard = false;
|
||||
|
||||
if (guard) {
|
||||
return;
|
||||
}
|
||||
|
||||
guard = true;
|
||||
QString ppath = package->path();
|
||||
if (ppath.endsWith('/')) {
|
||||
ppath.chop(1);
|
||||
if (!QFile::exists(ppath)) {
|
||||
ppath = package->path();
|
||||
}
|
||||
}
|
||||
|
||||
QFileInfo info(ppath);
|
||||
const bool isFullPackage = info.isDir();
|
||||
package->removeDefinition("preferred");
|
||||
package->setRequired("images", isFullPackage);
|
||||
|
||||
if (isFullPackage) {
|
||||
package->setContentsPrefixPaths(QStringList{QStringLiteral("contents/")});
|
||||
} else {
|
||||
package->addFileDefinition("screenshot", info.fileName());
|
||||
package->addFileDefinition("preferred", info.fileName());
|
||||
package->setContentsPrefixPaths(QStringList());
|
||||
package->setPath(info.path());
|
||||
}
|
||||
|
||||
guard = false;
|
||||
}
|
||||
};
|
||||
|
||||
class SimpleContent : public KPackage::PackageStructure
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
void initPackage(KPackage::Package *package) override
|
||||
{
|
||||
package->addDirectoryDefinition("ui", QStringLiteral("ui/"));
|
||||
}
|
||||
void pathChanged(KPackage::Package *package) override
|
||||
{
|
||||
if (!package->metadata().isValid()) {
|
||||
return;
|
||||
}
|
||||
if (readKPackageType(package->metadata()) == QStringLiteral("KPackage/CustomContent")) {
|
||||
package->addFileDefinition("customcontentfile", QStringLiteral("customcontent/CustomContentFile.qml"));
|
||||
} else {
|
||||
package->removeDefinition("customcontentfile");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void PackageStructureTest::initTestCase()
|
||||
{
|
||||
m_packagePath = QFINDTESTDATA("data/testpackage");
|
||||
ps = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML"));
|
||||
ps.setPath(m_packagePath);
|
||||
}
|
||||
|
||||
void PackageStructureTest::validStructures()
|
||||
{
|
||||
QVERIFY(ps.hasValidStructure());
|
||||
QVERIFY(!KPackage::Package().hasValidStructure());
|
||||
QVERIFY(!KPackage::PackageLoader::self()->loadPackage(QStringLiteral("doesNotExist")).hasValidStructure());
|
||||
}
|
||||
|
||||
void PackageStructureTest::validPackages()
|
||||
{
|
||||
QVERIFY(ps.isValid());
|
||||
QVERIFY(!KPackage::Package().isValid());
|
||||
QVERIFY(!KPackage::PackageLoader::self()->loadPackage(QStringLiteral("doesNotExist")).isValid());
|
||||
QVERIFY(NoPrefixes().isValid());
|
||||
|
||||
KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/Generic"));
|
||||
p.addFileDefinition("mainscript", QStringLiteral("ui/main.qml"));
|
||||
QVERIFY(!p.isValid());
|
||||
p.setPath(QStringLiteral("/does/not/exist"));
|
||||
QVERIFY(!p.isValid());
|
||||
p.setPath(ps.path());
|
||||
QVERIFY(p.isValid());
|
||||
}
|
||||
|
||||
void PackageStructureTest::wallpaperPackage()
|
||||
{
|
||||
KPackage::Package p(new Wallpaper);
|
||||
p.setPath(m_packagePath);
|
||||
QVERIFY(p.isValid());
|
||||
|
||||
KPackage::Package p2(new Wallpaper);
|
||||
p2.setPath(m_packagePath + "/contents/images/empty.png");
|
||||
QVERIFY(p2.isValid());
|
||||
}
|
||||
|
||||
void PackageStructureTest::mutateAfterCopy()
|
||||
{
|
||||
const bool mainscriptRequired = ps.isRequired("mainscript");
|
||||
const QStringList imageMimeTypes = ps.mimeTypes("images");
|
||||
const QStringList defaultMimeTypes = ps.mimeTypes("translations");
|
||||
const QString packageRoot = ps.defaultPackageRoot();
|
||||
const bool externalPaths = ps.allowExternalPaths();
|
||||
const QStringList contentsPrefixPaths = ps.contentsPrefixPaths();
|
||||
const QList<QByteArray> files = ps.files();
|
||||
const QList<QByteArray> dirs = ps.directories();
|
||||
|
||||
KPackage::Package copy(ps);
|
||||
|
||||
copy.setRequired("mainscript", !mainscriptRequired);
|
||||
QCOMPARE(ps.isRequired("mainscript"), mainscriptRequired);
|
||||
QCOMPARE(copy.isRequired("mainscript"), !mainscriptRequired);
|
||||
|
||||
copy = ps;
|
||||
const QString copyPackageRoot = packageRoot + "more/";
|
||||
copy.setDefaultPackageRoot(copyPackageRoot);
|
||||
QCOMPARE(ps.defaultPackageRoot(), packageRoot);
|
||||
QCOMPARE(copy.defaultPackageRoot(), copyPackageRoot);
|
||||
|
||||
copy = ps;
|
||||
copy.setAllowExternalPaths(!externalPaths);
|
||||
QCOMPARE(ps.allowExternalPaths(), externalPaths);
|
||||
QCOMPARE(copy.allowExternalPaths(), !externalPaths);
|
||||
|
||||
copy = ps;
|
||||
const QStringList copyContentsPrefixPaths = QStringList(contentsPrefixPaths) << QStringLiteral("more/");
|
||||
copy.setContentsPrefixPaths(copyContentsPrefixPaths);
|
||||
QCOMPARE(ps.contentsPrefixPaths(), contentsPrefixPaths);
|
||||
QCOMPARE(copy.contentsPrefixPaths(), copyContentsPrefixPaths);
|
||||
|
||||
copy = ps;
|
||||
copy.addFileDefinition("nonsense", QStringLiteral("foobar"));
|
||||
QCOMPARE(ps.files(), files);
|
||||
QVERIFY(ps.files() != copy.files());
|
||||
|
||||
copy = ps;
|
||||
copy.addDirectoryDefinition("nonsense", QStringLiteral("foobar"));
|
||||
QCOMPARE(ps.directories(), dirs);
|
||||
QVERIFY(ps.directories() != copy.directories());
|
||||
|
||||
copy = ps;
|
||||
copy.removeDefinition("mainscript");
|
||||
QCOMPARE(ps.files(), files);
|
||||
QVERIFY(ps.files() != copy.files());
|
||||
|
||||
copy = ps;
|
||||
QVERIFY(!imageMimeTypes.isEmpty());
|
||||
const QStringList copyMimeTypes(imageMimeTypes.first());
|
||||
copy.setMimeTypes("images", copyMimeTypes);
|
||||
QCOMPARE(ps.mimeTypes("images"), imageMimeTypes);
|
||||
QCOMPARE(copy.mimeTypes("images"), copyMimeTypes);
|
||||
|
||||
copy = ps;
|
||||
const QStringList copyDefaultMimeTypes = QStringList(defaultMimeTypes) << QStringLiteral("rubbish");
|
||||
copy.setDefaultMimeTypes(copyDefaultMimeTypes);
|
||||
QCOMPARE(ps.mimeTypes("translations"), defaultMimeTypes);
|
||||
QCOMPARE(copy.mimeTypes("translations"), copyDefaultMimeTypes);
|
||||
}
|
||||
|
||||
void PackageStructureTest::emptyContentsPrefix()
|
||||
{
|
||||
NoPrefixes package;
|
||||
QString path(package.filePath("bin", QStringLiteral("ls")));
|
||||
if (QFileInfo::exists(QStringLiteral("/bin/ls"))) { // not Windows
|
||||
QCOMPARE(path, QStringLiteral("/bin/ls"));
|
||||
}
|
||||
}
|
||||
|
||||
void PackageStructureTest::directories()
|
||||
{
|
||||
const QList<QByteArray> dirs{
|
||||
"config",
|
||||
"data",
|
||||
"images",
|
||||
"theme",
|
||||
"scripts",
|
||||
"translations",
|
||||
"ui",
|
||||
};
|
||||
|
||||
const QList<QByteArray> psDirs = ps.directories();
|
||||
|
||||
QCOMPARE(dirs.count(), psDirs.count());
|
||||
|
||||
for (const char *dir : psDirs) {
|
||||
bool found = false;
|
||||
for (const char *check : std::as_const(dirs)) {
|
||||
if (qstrcmp(dir, check)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QVERIFY(found);
|
||||
}
|
||||
|
||||
for (const char *dir : std::as_const(dirs)) {
|
||||
bool found = false;
|
||||
for (const char *check : psDirs) {
|
||||
if (qstrcmp(dir, check)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QVERIFY(found);
|
||||
}
|
||||
}
|
||||
|
||||
void PackageStructureTest::requiredDirectories()
|
||||
{
|
||||
QList<QByteArray> dirs;
|
||||
QCOMPARE(ps.requiredDirectories(), dirs);
|
||||
}
|
||||
|
||||
void PackageStructureTest::files()
|
||||
{
|
||||
const QList<QByteArray> files{
|
||||
"mainconfigui",
|
||||
"mainconfigxml",
|
||||
"mainscript",
|
||||
};
|
||||
|
||||
const QList<QByteArray> psFiles = ps.files();
|
||||
|
||||
for (const char *file : psFiles) {
|
||||
bool found = false;
|
||||
for (const char *check : std::as_const(files)) {
|
||||
if (qstrcmp(file, check)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QVERIFY(found);
|
||||
}
|
||||
}
|
||||
|
||||
void PackageStructureTest::requiredFiles()
|
||||
{
|
||||
const QList<QByteArray> files{"mainscript"};
|
||||
const QList<QByteArray> psFiles = ps.requiredFiles();
|
||||
QCOMPARE(files, psFiles);
|
||||
}
|
||||
|
||||
void PackageStructureTest::path()
|
||||
{
|
||||
QCOMPARE(ps.filePath("images"), QDir(m_packagePath + QLatin1String("/contents/images")).canonicalPath());
|
||||
QCOMPARE(ps.filePath("theme"), QString());
|
||||
QCOMPARE(ps.filePath("mainscript"), QFileInfo(m_packagePath + QLatin1String("/contents/ui/main.qml")).canonicalFilePath());
|
||||
}
|
||||
|
||||
void PackageStructureTest::required()
|
||||
{
|
||||
QVERIFY(ps.isRequired("mainscript"));
|
||||
}
|
||||
|
||||
void PackageStructureTest::mimeTypes()
|
||||
{
|
||||
const QStringList mimeTypes{QStringLiteral("image/svg+xml"), QStringLiteral("image/png"), QStringLiteral("image/jpeg")};
|
||||
QCOMPARE(ps.mimeTypes("images"), mimeTypes);
|
||||
QCOMPARE(ps.mimeTypes("theme"), mimeTypes);
|
||||
}
|
||||
|
||||
void PackageStructureTest::customContent()
|
||||
{
|
||||
KPackage::Package p(new SimpleContent);
|
||||
p.setPath(QFINDTESTDATA("data/simplecontent"));
|
||||
QVERIFY(p.isValid());
|
||||
QCOMPARE(p.filePath("customcontentfile"), QString());
|
||||
|
||||
p.setPath(QFINDTESTDATA("data/customcontent"));
|
||||
const QString expected = QFINDTESTDATA("data/customcontent") + "/contents/customcontent/CustomContentFile.qml";
|
||||
QCOMPARE(p.filePath("customcontentfile"), expected);
|
||||
QVERIFY(p.isValid());
|
||||
|
||||
p.setPath(QFINDTESTDATA("data/simplecontent"));
|
||||
QVERIFY(p.isValid());
|
||||
QCOMPARE(p.filePath("customcontentfile"), QString());
|
||||
}
|
||||
|
||||
QTEST_MAIN(PackageStructureTest)
|
||||
|
||||
#include "moc_packagestructuretest.cpp"
|
||||
#include "packagestructuretest.moc"
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
|
||||
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef PACKAGESTRUCTURETEST_H
|
||||
#define PACKAGESTRUCTURETEST_H
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include "kpackage/package.h"
|
||||
|
||||
class PackageStructureTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void validStructures();
|
||||
void validPackages();
|
||||
void wallpaperPackage();
|
||||
void mutateAfterCopy();
|
||||
void emptyContentsPrefix();
|
||||
void directories();
|
||||
void requiredDirectories();
|
||||
void files();
|
||||
void requiredFiles();
|
||||
void path();
|
||||
void required();
|
||||
void mimeTypes();
|
||||
void customContent();
|
||||
|
||||
private:
|
||||
KPackage::Package ps;
|
||||
QString m_packagePath;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Bertjan Broeksema <b.broeksema@kdemail.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "plasmoidpackagetest.h"
|
||||
#include "../src/kpackage/config-package.h"
|
||||
|
||||
#include <KJob>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QSignalSpy>
|
||||
#include <QStandardPaths>
|
||||
#include <kzip.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <qtestcase.h>
|
||||
|
||||
#include "packagejob.h"
|
||||
#include "packageloader.h"
|
||||
#include "private/utils.h"
|
||||
|
||||
void PlasmoidPackageTest::initTestCase()
|
||||
{
|
||||
QStandardPaths::setTestModeEnabled(true);
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::init()
|
||||
{
|
||||
qDebug() << "PlasmoidPackage::init()";
|
||||
qRegisterMetaType<KPackage::Package>(); // Needed for signal spy
|
||||
m_package = QStringLiteral("Package");
|
||||
m_packageRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/packageRoot";
|
||||
const auto pack = KPackage::PackageLoader::self()->loadPackageStructure("Plasma/TestKPackageInternalPlasmoid");
|
||||
QVERIFY(pack);
|
||||
m_defaultPackage = KPackage::Package(pack);
|
||||
cleanup(); // to prevent previous runs from interfering with this one
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::cleanup()
|
||||
{
|
||||
qDebug() << "cleaning up";
|
||||
// Clean things up.
|
||||
QDir(m_packageRoot).removeRecursively();
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::createTestPackage(const QString &packageName, const QString &version)
|
||||
{
|
||||
qDebug() << "Create test package" << m_packageRoot;
|
||||
QDir pRoot(m_packageRoot);
|
||||
// Create the root and package dir.
|
||||
if (!pRoot.exists()) {
|
||||
QVERIFY(QDir().mkpath(m_packageRoot));
|
||||
}
|
||||
|
||||
// Create the package dir
|
||||
QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName));
|
||||
qDebug() << "Created" << (m_packageRoot + "/" + packageName);
|
||||
|
||||
// Create the metadata.json file
|
||||
QFile file(m_packageRoot + "/" + packageName + "/metadata.json");
|
||||
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
|
||||
QJsonObject kplugin;
|
||||
kplugin.insert(QLatin1String("Id"), packageName);
|
||||
kplugin.insert(QLatin1String("Name"), packageName);
|
||||
kplugin.insert(QLatin1String("Version"), version);
|
||||
QJsonObject root{{QLatin1String("KPlugin"), kplugin}};
|
||||
|
||||
QTextStream out(&file);
|
||||
file.write(QJsonDocument(root).toJson());
|
||||
file.flush();
|
||||
file.close();
|
||||
|
||||
qDebug() << "OUT: " << packageName;
|
||||
|
||||
// Create the ui dir.
|
||||
QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/ui"));
|
||||
|
||||
// Create the main file.
|
||||
file.setFileName(m_packageRoot + "/" + packageName + "/contents/ui/main.qml");
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
|
||||
out << "THIS IS A PLASMOID SCRIPT.....";
|
||||
file.flush();
|
||||
file.close();
|
||||
|
||||
qDebug() << "THIS IS A PLASMOID SCRIPT THING";
|
||||
// Now we have a minimal plasmoid package which is valid. Let's add some
|
||||
// files to it for test purposes.
|
||||
|
||||
// Create the images dir.
|
||||
QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/images"));
|
||||
file.setFileName(m_packageRoot + "/" + packageName + "/contents/images/image-1.svg");
|
||||
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
|
||||
out << "<svg>This is a test image</svg>";
|
||||
file.flush();
|
||||
file.close();
|
||||
|
||||
file.setFileName(m_packageRoot + "/" + packageName + "/contents/images/image-2.svg");
|
||||
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
|
||||
out.setDevice(&file);
|
||||
out << "<svg>This is another test image</svg>";
|
||||
file.flush();
|
||||
file.close();
|
||||
|
||||
// Create the scripts dir.
|
||||
QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/code"));
|
||||
|
||||
// Create 2 js files
|
||||
file.setFileName(m_packageRoot + "/" + packageName + "/contents/code/script.js");
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
|
||||
out << "THIS IS A SCRIPT.....";
|
||||
file.flush();
|
||||
file.close();
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::isValid()
|
||||
{
|
||||
KPackage::Package p(m_defaultPackage);
|
||||
p.setPath(m_packageRoot + '/' + m_package);
|
||||
#ifndef NDEBUG
|
||||
qDebug() << "package path is" << p.path();
|
||||
#endif
|
||||
|
||||
// A PlasmoidPackage is valid when:
|
||||
// - The package root exists.
|
||||
// - The package root consists an file named "ui/main.qml"
|
||||
QVERIFY(!p.isValid());
|
||||
|
||||
// Create the root and package dir.
|
||||
QVERIFY(QDir().mkpath(m_packageRoot));
|
||||
QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package));
|
||||
|
||||
// Should still be invalid.
|
||||
p = KPackage::Package(m_defaultPackage);
|
||||
p.setPath(m_packageRoot + '/' + m_package);
|
||||
QVERIFY(!p.isValid());
|
||||
|
||||
// Create the ui dir.
|
||||
QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package + "/contents/ui"));
|
||||
|
||||
// No main file yet so should still be invalid.
|
||||
p = KPackage::Package(m_defaultPackage);
|
||||
p.setPath(m_packageRoot + '/' + m_package);
|
||||
QVERIFY(!p.isValid());
|
||||
|
||||
// Create the main file.
|
||||
QFile file(m_packageRoot + "/" + m_package + "/contents/ui/main.qml");
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
|
||||
QTextStream out(&file);
|
||||
out << "THIS IS A PLASMOID SCRIPT.....\n";
|
||||
file.flush();
|
||||
file.close();
|
||||
|
||||
file.setPermissions(QFile::ReadUser | QFile::WriteUser);
|
||||
// Main file exists so should be valid now.
|
||||
p = KPackage::Package(m_defaultPackage);
|
||||
p.setPath(m_packageRoot + '/' + m_package);
|
||||
QVERIFY(p.isValid());
|
||||
QCOMPARE(p.cryptographicHash(QCryptographicHash::Sha1), QByteArrayLiteral("468c7934dfa635986a85e3364363b1f39d157cd5"));
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::filePath()
|
||||
{
|
||||
// Package::filePath() returns
|
||||
// - {package_root}/{package_name}/path/to/file if the file exists
|
||||
// - QString() otherwise.
|
||||
KPackage::Package p(m_defaultPackage);
|
||||
p.setPath(m_packageRoot + '/' + m_package);
|
||||
|
||||
QCOMPARE(p.filePath("scripts", QStringLiteral("main")), QString());
|
||||
|
||||
QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package + "/contents/ui/"));
|
||||
QFile file(m_packageRoot + "/" + m_package + "/contents/ui/main.qml");
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
|
||||
QTextStream out(&file);
|
||||
out << "THIS IS A PLASMOID SCRIPT.....";
|
||||
file.flush();
|
||||
file.close();
|
||||
|
||||
// The package is valid by now so a path for code/main should get returned.
|
||||
p = KPackage::Package(m_defaultPackage);
|
||||
p.setPath(m_packageRoot + '/' + m_package);
|
||||
|
||||
const QString path = QFileInfo(m_packageRoot + "/" + m_package + "/contents/ui/main.qml").canonicalFilePath();
|
||||
|
||||
// Two ways to get the same info.
|
||||
// 1. Give the file type which refers to a class of files (a directory) in
|
||||
// the package structure and the file name.
|
||||
// 2. Give the file type which refers to a file in the package structure.
|
||||
//
|
||||
// NOTE: scripts, main and mainscript are defined in packages.cpp and are
|
||||
// specific for a PlasmoidPackage.
|
||||
QCOMPARE(p.filePath("mainscript"), path);
|
||||
QCOMPARE(p.filePath("ui", QStringLiteral("main.qml")), path);
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::entryList()
|
||||
{
|
||||
// Create a package named @p packageName which is valid and has some images.
|
||||
createTestPackage(m_package, QStringLiteral("1.1"));
|
||||
|
||||
// Create a package object and verify that it is valid.
|
||||
KPackage::Package p(m_defaultPackage);
|
||||
p.setPath(m_packageRoot + '/' + m_package);
|
||||
QVERIFY(p.isValid());
|
||||
|
||||
// Now we have a valid package that should contain the following files in
|
||||
// given filetypes:
|
||||
// fileTye - Files
|
||||
// scripts - {"script.js"}
|
||||
// images - {"image-1.svg", "image-2.svg"}
|
||||
QStringList files = p.entryList("scripts");
|
||||
QCOMPARE(files.size(), 1);
|
||||
QVERIFY(files.contains(QStringLiteral("script.js")));
|
||||
|
||||
files = p.entryList("images");
|
||||
QCOMPARE(files.size(), 2);
|
||||
QVERIFY(files.contains(QStringLiteral("image-1.svg")));
|
||||
QVERIFY(files.contains(QStringLiteral("image-2.svg")));
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::createAndInstallPackage()
|
||||
{
|
||||
qDebug() << " ";
|
||||
qDebug() << " CreateAndInstall ";
|
||||
createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
|
||||
const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
|
||||
|
||||
KZip creator(packagePath);
|
||||
QVERIFY(creator.open(QIODevice::WriteOnly));
|
||||
creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
|
||||
creator.close();
|
||||
QDir rootDir(m_packageRoot + "/plasmoid_to_package");
|
||||
rootDir.removeRecursively();
|
||||
|
||||
QVERIFY2(QFile::exists(packagePath), qPrintable(packagePath));
|
||||
|
||||
KZip package(packagePath);
|
||||
QVERIFY(package.open(QIODevice::ReadOnly));
|
||||
const KArchiveDirectory *dir = package.directory();
|
||||
QVERIFY(dir); //
|
||||
QVERIFY(dir->entry(QStringLiteral("metadata.json")));
|
||||
const KArchiveEntry *contentsEntry = dir->entry(QStringLiteral("contents"));
|
||||
QVERIFY(contentsEntry);
|
||||
QVERIFY(contentsEntry->isDirectory());
|
||||
const KArchiveDirectory *contents = static_cast<const KArchiveDirectory *>(contentsEntry);
|
||||
QVERIFY(contents->entry(QStringLiteral("ui")));
|
||||
QVERIFY(contents->entry(QStringLiteral("images")));
|
||||
|
||||
KPackage::PackageLoader::self()->addKnownPackageStructure(m_defaultPackageStructure, new KPackage::PackageStructure(this));
|
||||
KPackage::Package p;
|
||||
qDebug() << "Installing " << packagePath;
|
||||
auto job = KPackage::PackageJob::install(m_defaultPackageStructure, packagePath, m_packageRoot);
|
||||
connect(job, &KJob::finished, this, [&p, job]() { // clazy:exclude=lambda-in-connect
|
||||
p = job->package();
|
||||
});
|
||||
QSignalSpy spy(job, &KJob::finished);
|
||||
QVERIFY(spy.wait(1000));
|
||||
|
||||
// is the package instance usable (ie proper path) after the install job has been completed?
|
||||
QCOMPARE(p.path(), QString(QDir(m_packageRoot % "/plasmoid_to_package").canonicalPath() + QLatin1Char('/')));
|
||||
cleanupPackage(QStringLiteral("plasmoid_to_package"));
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::createAndUpdatePackage()
|
||||
{
|
||||
// does the version number parsing work?
|
||||
QVERIFY(isVersionNewer(QStringLiteral("1.1"), QStringLiteral("1.1.1")));
|
||||
QVERIFY(!isVersionNewer(QStringLiteral("1.1.1"), QStringLiteral("1.1")));
|
||||
QVERIFY(isVersionNewer(QStringLiteral("1.1.1"), QStringLiteral("1.1.2")));
|
||||
QVERIFY(isVersionNewer(QStringLiteral("1.1.2"), QStringLiteral("2.1")));
|
||||
QVERIFY(isVersionNewer(QStringLiteral("0.1.2"), QStringLiteral("2")));
|
||||
QVERIFY(!isVersionNewer(QStringLiteral("1"), QStringLiteral("0.1.2")));
|
||||
|
||||
qDebug() << " ";
|
||||
qDebug() << " CreateAndUpdate ";
|
||||
createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
|
||||
const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
|
||||
|
||||
KZip creator(packagePath);
|
||||
QVERIFY(creator.open(QIODevice::WriteOnly));
|
||||
creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
|
||||
creator.close();
|
||||
QDir rootDir(m_packageRoot + "/plasmoid_to_package");
|
||||
rootDir.removeRecursively();
|
||||
|
||||
QVERIFY(QFile::exists(packagePath));
|
||||
|
||||
KZip package(packagePath);
|
||||
QVERIFY(package.open(QIODevice::ReadOnly));
|
||||
const KArchiveDirectory *dir = package.directory();
|
||||
QVERIFY(dir); //
|
||||
QVERIFY(dir->entry(QStringLiteral("metadata.json")));
|
||||
const KArchiveEntry *contentsEntry = dir->entry(QStringLiteral("contents"));
|
||||
QVERIFY(contentsEntry);
|
||||
QVERIFY(contentsEntry->isDirectory());
|
||||
const KArchiveDirectory *contents = static_cast<const KArchiveDirectory *>(contentsEntry);
|
||||
QVERIFY(contents->entry(QStringLiteral("ui")));
|
||||
QVERIFY(contents->entry(QStringLiteral("images")));
|
||||
|
||||
qDebug() << "Installing " << packagePath;
|
||||
|
||||
KJob *job = KPackage::PackageJob::update(m_defaultPackageStructure, packagePath, m_packageRoot);
|
||||
connect(job, &KJob::finished, [this, job]() {
|
||||
packageInstalled(job);
|
||||
});
|
||||
QSignalSpy spy(job, &KJob::finished);
|
||||
QVERIFY(spy.wait(1000));
|
||||
|
||||
// same version, should fail
|
||||
job = KPackage::PackageJob::update(m_defaultPackageStructure, packagePath, m_packageRoot);
|
||||
QSignalSpy spyFail(job, &KJob::finished);
|
||||
QVERIFY(spyFail.wait(1000));
|
||||
QVERIFY(job->error() == KPackage::PackageJob::JobError::NewerVersionAlreadyInstalledError);
|
||||
qDebug() << job->errorText();
|
||||
|
||||
// create a new package with higher version
|
||||
createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.2"));
|
||||
|
||||
KZip creator2(packagePath);
|
||||
QVERIFY(creator2.open(QIODevice::WriteOnly));
|
||||
creator2.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
|
||||
creator2.close();
|
||||
QDir rootDir2(m_packageRoot + "/plasmoid_to_package");
|
||||
rootDir2.removeRecursively();
|
||||
|
||||
KJob *job2 = KPackage::PackageJob::update(m_defaultPackageStructure, packagePath, m_packageRoot);
|
||||
connect(job2, &KJob::finished, [this, job2]() {
|
||||
packageInstalled(job2);
|
||||
});
|
||||
QSignalSpy spy2(job2, &KJob::finished);
|
||||
QVERIFY(spy2.wait(1000));
|
||||
|
||||
cleanupPackage(QStringLiteral("plasmoid_to_package"));
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::uncompressPackageWithSubFolder()
|
||||
{
|
||||
KPackage::PackageStructure *structure = new KPackage::PackageStructure;
|
||||
KPackage::Package package(structure);
|
||||
package.setPath(QFINDTESTDATA("data/customcontent.tar.gz"));
|
||||
|
||||
QCOMPARE(readKPackageType(package.metadata()), "KPackage/CustomContent");
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::cleanupPackage(const QString &packageName)
|
||||
{
|
||||
KJob *j = KPackage::PackageJob::uninstall(m_defaultPackageStructure, packageName, m_packageRoot);
|
||||
connect(j, &KJob::finished, [this, j]() {
|
||||
packageUninstalled(j);
|
||||
});
|
||||
|
||||
QSignalSpy spy(j, &KJob::finished);
|
||||
QVERIFY(spy.wait(1000));
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::packageInstalled(KJob *j)
|
||||
{
|
||||
QVERIFY2(j->error() == KJob::NoError, qPrintable(j->errorText()));
|
||||
}
|
||||
|
||||
void PlasmoidPackageTest::packageUninstalled(KJob *j)
|
||||
{
|
||||
QVERIFY2(j->error() == KJob::NoError, qPrintable(j->errorText()));
|
||||
}
|
||||
void PlasmoidPackageTest::testInstallNonExistentPackageStructure()
|
||||
{
|
||||
const QString packageName = "testpackage";
|
||||
createTestPackage(packageName, "1.0");
|
||||
auto job = KPackage::PackageJob::install("KPackage/DoesNotExist", packageName, m_packageRoot);
|
||||
connect(job, &KJob::result, this, [job]() {
|
||||
QVERIFY(!job->package().isValid());
|
||||
QCOMPARE(job->error(), KPackage::PackageJob::JobError::InvalidPackageStructure);
|
||||
QCOMPARE(job->errorText(), "Could not load package structure KPackage/DoesNotExist");
|
||||
});
|
||||
QSignalSpy spy(job, &KJob::result);
|
||||
QVERIFY(spy.wait(1000));
|
||||
}
|
||||
|
||||
QTEST_MAIN(PlasmoidPackageTest)
|
||||
|
||||
#include "moc_plasmoidpackagetest.cpp"
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Bertjan Broeksema <b.broeksema@kdemail.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef PACKAGETEST_H
|
||||
#define PACKAGETEST_H
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include "kpackage/package.h"
|
||||
#include "kpackage/packagestructure.h"
|
||||
|
||||
class PlasmoidPackageTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public Q_SLOTS:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
private Q_SLOTS:
|
||||
void createAndInstallPackage();
|
||||
void createAndUpdatePackage();
|
||||
void uncompressPackageWithSubFolder();
|
||||
void isValid();
|
||||
void filePath();
|
||||
void entryList();
|
||||
void testInstallNonExistentPackageStructure();
|
||||
|
||||
void packageInstalled(KJob *j);
|
||||
void packageUninstalled(KJob *j);
|
||||
|
||||
private:
|
||||
void createTestPackage(const QString &packageName, const QString &version);
|
||||
void cleanupPackage(const QString &packageName);
|
||||
|
||||
QString m_packageRoot;
|
||||
QString m_package;
|
||||
KPackage::Package m_defaultPackage;
|
||||
const QString m_defaultPackageStructure = "KPackage/Test";
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
|
||||
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "querytest.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QCoreApplication>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "packagejob.h"
|
||||
#include "packageloader.h"
|
||||
#include "packagestructure.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void QueryTest::initTestCase()
|
||||
{
|
||||
QStandardPaths::setTestModeEnabled(true);
|
||||
// Remove any eventual installed package globally on the system
|
||||
qputenv("XDG_DATA_DIRS", "/not/valid");
|
||||
qputenv("KPACKAGE_DEP_RESOLVERS_PATH", KPACKAGE_DEP_RESOLVERS);
|
||||
|
||||
m_dataDir = QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
|
||||
|
||||
// verify that the test plugin if found
|
||||
QVERIFY(KPackage::PackageLoader::self()->loadPackageStructure("Plasma/TestKPackageInternalPlasmoid"));
|
||||
}
|
||||
|
||||
static bool checkedInstall(const QString &packageFormat, const QString &source, int expectedError)
|
||||
{
|
||||
auto job = KPackage::PackageJob::install(packageFormat, source, {});
|
||||
QEventLoop l;
|
||||
QObject::connect(job, &KJob::result, &l, [&l]() {
|
||||
l.quit();
|
||||
});
|
||||
l.exec();
|
||||
if (job->error() == expectedError) {
|
||||
return true;
|
||||
}
|
||||
qWarning() << "Unexpected error" << job->error() << "while installing" << source << job->errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
void QueryTest::installAndQuery()
|
||||
{
|
||||
m_dataDir.removeRecursively();
|
||||
// verify that no packages are installed
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 0);
|
||||
|
||||
// install some packages
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testpackage"), KJob::NoError));
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testfallbackpackage"), KJob::NoError));
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 2);
|
||||
|
||||
// installing package with invalid metadata should not be possible
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testinvalidmetadata"), KPackage::PackageJob::PluginIdInvalidError));
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 2);
|
||||
|
||||
// package with valid dep information should be installed
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testpackagesdep"), KJob::NoError));
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 3);
|
||||
|
||||
// package with invalid dep information should not be installed
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testpackagesdepinvalid"), KPackage::PackageJob::JobError::PackageCopyError));
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 3);
|
||||
}
|
||||
|
||||
void QueryTest::queryCustomPlugin()
|
||||
{
|
||||
m_dataDir.removeRecursively();
|
||||
|
||||
// verify that no packages are installed
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 0);
|
||||
|
||||
auto testPackageStructure = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/TestKPackageInternalPlasmoid"));
|
||||
// install some packages
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testpackage"), KJob::NoError));
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testfallbackpackage"), KJob::NoError));
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 2);
|
||||
|
||||
// installing package with invalid metadata should not be possible
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testinvalidmetadata"), KPackage::PackageJob::JobError::PluginIdInvalidError));
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 2);
|
||||
|
||||
// package with valid dep information should be installed
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testpackagesdep"), KJob::NoError));
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 3);
|
||||
|
||||
// package with invalid dep information should not be installed
|
||||
QVERIFY(checkedInstall(packageFormat, QFINDTESTDATA("data/testpackagesdepinvalid"), KPackage::PackageJob::JobError::PackageCopyError));
|
||||
|
||||
QCOMPARE(KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/TestKPackageInternalPlasmoid")).count(), 3);
|
||||
}
|
||||
|
||||
QTEST_MAIN(QueryTest)
|
||||
|
||||
#include "moc_querytest.cpp"
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
|
||||
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef PACKAGESTRUCTURETEST_H
|
||||
#define PACKAGESTRUCTURETEST_H
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include "kpackage/package.h"
|
||||
|
||||
class QueryTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void installAndQuery();
|
||||
void queryCustomPlugin();
|
||||
|
||||
private:
|
||||
const QString packageFormat = "Plasma/TestKPackageInternalPlasmoid";
|
||||
QDir m_dataDir;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user