mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
Minor fixes + tests + getSupportURL().
This commit is contained in:
@@ -27,6 +27,8 @@ add_subdirectory(src/proxy)
|
||||
# force plugin_python to build mobase
|
||||
add_dependencies(plugin_python mobase)
|
||||
|
||||
set(PLUGIN_PYTHON_TESTS ${PLUGIN_PYTHON_TESTS} CACHE BOOL "build tests for plugin_python")
|
||||
|
||||
if (PLUGIN_PYTHON_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -520,7 +520,11 @@ namespace mo2::python {
|
||||
DWORD returnCode;
|
||||
bool result =
|
||||
o->waitForApplication((HANDLE)handle, refresh, &returnCode);
|
||||
return std::make_tuple(result, returnCode);
|
||||
|
||||
// we force signed return code because it's probably what's expected
|
||||
// in Python
|
||||
return std::make_tuple(
|
||||
result, static_cast<std::make_signed_t<DWORD>>(returnCode));
|
||||
},
|
||||
"handle"_a, "refresh"_a = true)
|
||||
|
||||
|
||||
@@ -89,7 +89,8 @@ namespace mo2::python {
|
||||
.def("nexusGameID", &IPluginGame::nexusGameID)
|
||||
.def("looksValid", &IPluginGame::looksValid, "directory"_a)
|
||||
.def("gameVersion", &IPluginGame::gameVersion)
|
||||
.def("getLauncherName", &IPluginGame::getLauncherName);
|
||||
.def("getLauncherName", &IPluginGame::getLauncherName)
|
||||
.def("getSupportURL", &IPluginGame::getSupportURL);
|
||||
}
|
||||
|
||||
// multiple installers
|
||||
|
||||
@@ -479,6 +479,10 @@ namespace mo2::python {
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, getLauncherName, );
|
||||
}
|
||||
QString getSupportURL() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE(QString, IPluginGame, getSupportURL, );
|
||||
}
|
||||
|
||||
protected:
|
||||
std::map<std::type_index, std::any> featureList() const override;
|
||||
|
||||
@@ -139,9 +139,8 @@ namespace pybind11::detail {
|
||||
return type_caster<QStringList>::cast(var.toStringList(), policy, parent);
|
||||
case QVariant::List:
|
||||
return type_caster<QVariantList>::cast(var.toList(), policy, parent);
|
||||
case QVariant::Map: // return
|
||||
// type_caster<QVariantMap>::cast(var.toList(),
|
||||
// policy, parent);
|
||||
case QVariant::Map:
|
||||
return type_caster<QVariantMap>::cast(var.toMap(), policy, parent);
|
||||
default: {
|
||||
PyErr_Format(PyExc_TypeError, "type unsupported: %d", var.type());
|
||||
throw pybind11::error_already_set();
|
||||
|
||||
+2
-44
@@ -1,46 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(PYLIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/pylibs)
|
||||
|
||||
if (TARGET uibase)
|
||||
set(UIBASE_PATH $<TARGET_FILE:uibase>)
|
||||
else()
|
||||
set(UIBASE_PATH "${MO2_INSTALL_PATH}/bin/uibase.dll")
|
||||
endif()
|
||||
|
||||
add_custom_target(pytest
|
||||
${CMAKE_COMMAND} -E env
|
||||
PYTHONPATH="${PYLIB_DIR}\\;$<TARGET_FILE_DIR:mobase>"
|
||||
"UIBASE_PATH=${UIBASE_PATH}" "QT_ROOT=${QT_ROOT}"
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pylibs/bin/pytest.exe ${CMAKE_CURRENT_SOURCE_DIR}/../tests -s
|
||||
WORKING_DIRECTORY ${MO2_INSTALL_PATH}
|
||||
|
||||
)
|
||||
mo2_python_pip_install(pytest
|
||||
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pylibs
|
||||
PACKAGES pytest PyQt6==6.3.0)
|
||||
add_dependencies(pytest mobase)
|
||||
|
||||
|
||||
file(GLOB test_files CONFIGURE_DEPENDS "test_*.cpp")
|
||||
foreach (test_file ${test_files})
|
||||
get_filename_component(target ${test_file} NAME_WLE)
|
||||
string(REPLACE "test_" "" pymodule ${target})
|
||||
pybind11_add_module(${target} THIN_LTO ${test_file})
|
||||
set_target_properties(${target}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME ${pymodule}
|
||||
LIBRARY_OUTPUT_DIRECTORY "${PYLIB_DIR}/mobase_tests")
|
||||
|
||||
if(DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER ${config} config)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY_${config} "${PYLIB_DIR}/mobase_tests")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
mo2_add_dependencies(${target} PRIVATE uibase Qt::Core Qt::Widgets)
|
||||
target_link_libraries(${target} PRIVATE pybind11::qt)
|
||||
add_dependencies(pytest ${target})
|
||||
endforeach()
|
||||
add_subdirectory(python)
|
||||
add_subdirectory(runner)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "imoinfo.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace MOBase;
|
||||
|
||||
class MockOrganizer : public IOrganizer {
|
||||
public:
|
||||
// clang-format off
|
||||
MOCK_METHOD(IModRepositoryBridge*, createNexusBridge, (), (const, override));
|
||||
MOCK_METHOD(QString, profileName, (), (const, override));
|
||||
MOCK_METHOD(QString, profilePath, (), (const, override));
|
||||
MOCK_METHOD(QString, downloadsPath, (), (const, override));
|
||||
MOCK_METHOD(QString, overwritePath, (), (const, override));
|
||||
MOCK_METHOD(QString, basePath, (), (const, override));
|
||||
MOCK_METHOD(QString, modsPath, (), (const, override));
|
||||
MOCK_METHOD(VersionInfo, appVersion, (), (const, override));
|
||||
MOCK_METHOD(IModInterface*, createMod, (GuessedValue<QString> &name), (override));
|
||||
MOCK_METHOD(IPluginGame*, getGame, (const QString &gameName), (const, override));
|
||||
MOCK_METHOD(void, modDataChanged, (IModInterface *mod), (override));
|
||||
MOCK_METHOD(QVariant, pluginSetting, (const QString &pluginName, const QString &key), (const, override));
|
||||
MOCK_METHOD(void, setPluginSetting, (const QString &pluginName, const QString &key, const QVariant &value), (override));
|
||||
MOCK_METHOD(bool, isPluginEnabled, (const QString& pluginName), (const, override));
|
||||
MOCK_METHOD(bool, isPluginEnabled, (IPlugin *plugin), (const, override));
|
||||
MOCK_METHOD(QVariant, persistent, (const QString &pluginName, const QString &key, const QVariant &def), (const, override));
|
||||
MOCK_METHOD(void, setPersistent, (const QString &pluginName, const QString &key, const QVariant &value, bool sync), (override));
|
||||
MOCK_METHOD(QString, pluginDataPath, (), (const, override));
|
||||
MOCK_METHOD(IModInterface*, installMod, (const QString &fileName, const QString &nameSuggestion), (override));
|
||||
MOCK_METHOD(QString, resolvePath, (const QString &fileName), (const, override));
|
||||
MOCK_METHOD(QStringList, listDirectories, (const QString &directoryName), (const, override));
|
||||
MOCK_METHOD(QStringList, findFiles, (const QString &path, const std::function<bool(const QString&)> &filter), (const, override));
|
||||
MOCK_METHOD(QStringList, findFiles, (const QString &path, const QStringList &filter), (const, override));
|
||||
MOCK_METHOD(QStringList, getFileOrigins, (const QString &fileName) ,(const, override));
|
||||
MOCK_METHOD(QList<FileInfo>, findFileInfos, (const QString &path, const std::function<bool(const FileInfo&)> &filter), (const, override));
|
||||
MOCK_METHOD(std::shared_ptr<const IFileTree>, virtualFileTree, (), (const, override));
|
||||
MOCK_METHOD(MOBase::IDownloadManager*, downloadManager, (), (const, override));
|
||||
MOCK_METHOD(MOBase::IPluginList*, pluginList, (), (const, override));
|
||||
MOCK_METHOD(MOBase::IModList*, modList, (), (const, override));
|
||||
MOCK_METHOD(MOBase::IProfile*, profile, (), (const, override));
|
||||
MOCK_METHOD(HANDLE, startApplication, (const QString &executable, const QStringList &args, const QString &cwd, const QString &profile, const QString &forcedCustomOverwrite, bool ignoreCustomOverwrite), (override));
|
||||
MOCK_METHOD(bool, waitForApplication, (HANDLE handle, bool refresh, LPDWORD exitCode), (const, override));
|
||||
MOCK_METHOD(bool, onAboutToRun, (const std::function<bool(const QString&)> &func), (override));
|
||||
MOCK_METHOD(bool, onFinishedRun, (const std::function<void(const QString&, unsigned int)> &func), (override));
|
||||
MOCK_METHOD(void, refresh, (bool saveChanges), (override));
|
||||
MOCK_METHOD(MOBase::IPluginGame const *, managedGame, (), (const, override));
|
||||
MOCK_METHOD(bool, onUserInterfaceInitialized, (const std::function<void (QMainWindow *)> &), (override));
|
||||
MOCK_METHOD(bool, onProfileCreated, (const std::function<void(MOBase::IProfile*)>&), (override));
|
||||
MOCK_METHOD(bool, onProfileRemoved, (const std::function<void(const QString&)>&), (override));
|
||||
MOCK_METHOD(bool, onProfileRenamed, (const std::function<void(MOBase::IProfile*, QString const&, QString const&)>&), (override));
|
||||
MOCK_METHOD(bool, onProfileChanged, (const std::function<void (MOBase::IProfile*, MOBase::IProfile*)> &), (override));
|
||||
MOCK_METHOD(bool, onPluginSettingChanged, (const std::function<void (const QString &,const QString &,const QVariant &,const QVariant &)> &), (override));
|
||||
MOCK_METHOD(bool, onPluginEnabled, (const std::function<void(const MOBase::IPlugin*)>&), (override));
|
||||
MOCK_METHOD(bool, onPluginEnabled, (const QString&, const std::function<void()>&), (override));
|
||||
MOCK_METHOD(bool, onPluginDisabled, (const std::function<void(const MOBase::IPlugin*)>&), (override));
|
||||
MOCK_METHOD(bool, onPluginDisabled, (const QString&, const std::function<void()>&), (override));
|
||||
// clang-format on
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# pytest
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
set(PYLIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/pylibs)
|
||||
|
||||
if (TARGET uibase)
|
||||
set(UIBASE_PATH $<TARGET_FILE:uibase>)
|
||||
else()
|
||||
set(UIBASE_PATH "${MO2_INSTALL_PATH}/bin/uibase.dll")
|
||||
endif()
|
||||
|
||||
add_custom_target(pytest
|
||||
${CMAKE_COMMAND} -E env
|
||||
PYTHONPATH="${PYLIB_DIR}\\;$<TARGET_FILE_DIR:mobase>"
|
||||
"UIBASE_PATH=${UIBASE_PATH}" "QT_ROOT=${QT_ROOT}"
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pylibs/bin/pytest.exe ${CMAKE_CURRENT_SOURCE_DIR} -s
|
||||
WORKING_DIRECTORY ${MO2_INSTALL_PATH}
|
||||
|
||||
)
|
||||
mo2_python_pip_install(pytest
|
||||
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pylibs
|
||||
PACKAGES pytest PyQt6==6.3.0)
|
||||
add_dependencies(pytest mobase)
|
||||
|
||||
|
||||
file(GLOB test_files CONFIGURE_DEPENDS "test_*.cpp")
|
||||
foreach (test_file ${test_files})
|
||||
get_filename_component(target ${test_file} NAME_WLE)
|
||||
|
||||
string(REPLACE "test_" "" pymodule ${target})
|
||||
pybind11_add_module(${target} THIN_LTO ${test_file})
|
||||
set_target_properties(${target}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME ${pymodule}
|
||||
LIBRARY_OUTPUT_DIRECTORY "${PYLIB_DIR}/mobase_tests")
|
||||
|
||||
if(DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(config ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER ${config} config)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY_${config} "${PYLIB_DIR}/mobase_tests")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
mo2_add_dependencies(${target} PRIVATE uibase Qt::Core Qt::Widgets)
|
||||
# set_property(TARGET ${target} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
|
||||
target_link_libraries(${target} PRIVATE pybind11::qt GTest::gmock)
|
||||
|
||||
target_include_directories(${target}
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../mocks)
|
||||
add_dependencies(pytest ${target})
|
||||
endforeach()
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "pybind11_qt/pybind11_qt.h"
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include <QMap>
|
||||
#include <QWidget>
|
||||
|
||||
#include "MockOrganizer.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace pybind11::literals;
|
||||
using ::testing::NiceMock;
|
||||
|
||||
PYBIND11_MODULE(organizer, m)
|
||||
{
|
||||
m.def(
|
||||
"organizer",
|
||||
[]() -> IOrganizer* {
|
||||
MockOrganizer* mock = new NiceMock<MockOrganizer>();
|
||||
ON_CALL(*mock, profileName).WillByDefault([&mock]() {
|
||||
return "profile";
|
||||
});
|
||||
const auto handle = (HANDLE)std::uintptr_t{4654};
|
||||
ON_CALL(*mock, startApplication).WillByDefault([&mock, handle](auto&&...) {
|
||||
return handle;
|
||||
});
|
||||
ON_CALL(*mock, waitForApplication)
|
||||
.WillByDefault([&mock, original_handle = handle](
|
||||
HANDLE handle, bool refresh, LPDWORD exitCode) {
|
||||
if (handle == original_handle) {
|
||||
*exitCode = 0;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
*exitCode = -1;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return mock;
|
||||
},
|
||||
py::return_value_policy::take_ownership);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import pytest
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
|
||||
m = pytest.importorskip("mobase_tests.organizer")
|
||||
|
||||
|
||||
def test_getters():
|
||||
o = m.organizer()
|
||||
assert o.profileName() == "profile"
|
||||
assert o.startApplication("") == 4654
|
||||
assert o.waitForApplication(42) == (False, -1)
|
||||
assert o.waitForApplication(4654) == (True, 0)
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <QMap>
|
||||
#include <QWidget>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace py = pybind11;
|
||||
using namespace pybind11::literals;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
add_executable(pythonrunner-tests)
|
||||
mo2_configure_tests(pythonrunner-tests
|
||||
WARNINGS OFF)
|
||||
mo2_add_dependencies(pythonrunner-tests PUBLIC uibase)
|
||||
target_include_directories(pythonrunner-tests
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../mocks)
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "MockOrganizer.h"
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::NaggyMock;
|
||||
using ::testing::Return;
|
||||
|
||||
TEST(Organizer, Basic)
|
||||
{
|
||||
MockOrganizer mock;
|
||||
}
|
||||
Reference in New Issue
Block a user