diff --git a/src/mobase/wrappers/basic_classes.cpp b/src/mobase/wrappers/basic_classes.cpp index 7947bae..ef5a810 100644 --- a/src/mobase/wrappers/basic_classes.cpp +++ b/src/mobase/wrappers/basic_classes.cpp @@ -33,6 +33,69 @@ namespace mo2::python { void add_versioninfo_classes(py::module_ m) { + // Version + py::class_ pyVersion(m, "Version"); + + py::enum_(pyVersion, "ReleaseType") + .value("DEVELOPMENT", Version::Development) + .value("ALPHA", Version::Alpha) + .value("BETA", Version::Beta) + .value("RELEASE_CANDIDATE", Version::ReleaseCandidate) + .export_values(); + + py::enum_(pyVersion, "ParseMode") + .value("SEMVER", Version::ParseMode::SemVer) + .value("MO2", Version::ParseMode::MO2); + + py::enum_(pyVersion, "FormatMode", py::arithmetic{}) + .value("FORCE_SUBPATCH", Version::FormatMode::ForceSubPatch) + .value("NO_SEPARATOR", Version::FormatMode::NoSeparator) + .value("SHORT_ALPHA_BETA", Version::FormatMode::ShortAlphaBeta) + .value("NO_METADATA", Version::FormatMode::NoMetadata) + .value("CONDENSED", + static_cast(Version::FormatCondensed.toInt())) + .export_values(); + + pyVersion + .def_static("parse", &Version::parse, "value"_a, + "mode"_a = Version::ParseMode::SemVer) + .def(py::init(), "major"_a, "minor"_a, "patch"_a, + "metadata"_a = "") + .def(py::init(), "major"_a, "minor"_a, + "patch"_a, "subpatch"_a, "metadata"_a = "") + .def(py::init(), "major"_a, + "minor"_a, "patch"_a, "type"_a, "metadata"_a = "") + .def(py::init(), + "major"_a, "minor"_a, "patch"_a, "subpatch"_a, "type"_a, + "metadata"_a = "") + .def(py::init(), + "major"_a, "minor"_a, "patch"_a, "type"_a, "prerelease"_a, + "metadata"_a = "") + .def(py::init(), + "major"_a, "minor"_a, "patch"_a, "subpatch"_a, "type"_a, + "prerelease"_a, "metadata"_a = "") + .def(py::init>, + QString>(), + "major"_a, "minor"_a, "patch"_a, "subpatch"_a, "prereleases"_a, + "metadata"_a = "") + .def("isPreRelease", &Version::isPreRelease) + .def_property_readonly("major", &Version::major) + .def_property_readonly("minor", &Version::minor) + .def_property_readonly("patch", &Version::patch) + .def_property_readonly("subpatch", &Version::subpatch) + .def_property_readonly("prereleases", &Version::preReleases) + .def_property_readonly("build_metadata", &Version::buildMetadata) + .def("string", &Version::string, "mode"_a = Version::FormatCondensed) + .def("__str__", &Version::string) + .def(py::self < py::self) + .def(py::self > py::self) + .def(py::self <= py::self) + .def(py::self >= py::self) + .def(py::self != py::self) + .def(py::self == py::self); + + // VersionInfo py::enum_(m, "ReleaseType") .value("final", MOBase::VersionInfo::RELEASE_FINAL) .value("candidate", MOBase::VersionInfo::RELEASE_CANDIDATE) @@ -451,7 +514,17 @@ namespace mo2::python { .def("overwritePath", &IOrganizer::overwritePath) .def("basePath", &IOrganizer::basePath) .def("modsPath", &IOrganizer::modsPath) - .def("appVersion", &IOrganizer::appVersion) + .def("appVersion", + [](IOrganizer& o) { + mo2::python::show_deprecation_warning( + "appVersion", "IOrganizer::appVersion() is deprecated, use " + "IOrganizer::version() instead."); +#pragma warning(push) +#pragma warning(disable : 4996) + return o.appVersion(); +#pragma warning(pop) + }) + .def("version", &IOrganizer::version) .def("createMod", &IOrganizer::createMod, py::return_value_policy::reference, "name"_a) .def("getGame", &IOrganizer::getGame, py::return_value_policy::reference, diff --git a/tests/mocks/MockOrganizer.h b/tests/mocks/MockOrganizer.h index 2a7a968..cdae36a 100644 --- a/tests/mocks/MockOrganizer.h +++ b/tests/mocks/MockOrganizer.h @@ -14,6 +14,7 @@ class MockOrganizer : public IOrganizer { MOCK_METHOD(QString, basePath, (), (const, override)); MOCK_METHOD(QString, modsPath, (), (const, override)); MOCK_METHOD(VersionInfo, appVersion, (), (const, override)); + MOCK_METHOD(Version, version, (), (const, override)); MOCK_METHOD(IModInterface*, createMod, (GuessedValue &name), (override)); MOCK_METHOD(IPluginGame*, getGame, (const QString &gameName), (const, override)); MOCK_METHOD(void, modDataChanged, (IModInterface *mod), (override)); diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 7ca7d4f..f91af55 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -53,6 +53,7 @@ foreach (test_file ${test_files}) pybind11_add_module(${target} EXCLUDE_FROM_ALL THIN_LTO ${test_file}) set_target_properties(${target} PROPERTIES + CXX_STANDARD 20 OUTPUT_NAME ${pymodule} FOLDER tests/python LIBRARY_OUTPUT_DIRECTORY "${PYLIB_DIR}/mobase_tests") diff --git a/tests/python/test_organizer.cpp b/tests/python/test_organizer.cpp index 9a18f7c..ea54c0d 100644 --- a/tests/python/test_organizer.cpp +++ b/tests/python/test_organizer.cpp @@ -17,32 +17,30 @@ PYBIND11_MODULE(organizer, m) using ::testing::Eq; using ::testing::Return; - m.def( - "organizer", - []() -> IOrganizer* { - MockOrganizer* mock = new NiceMock(); - ON_CALL(*mock, profileName).WillByDefault([&mock]() { - return "profile"; + m.def("organizer", []() -> IOrganizer* { + MockOrganizer* mock = new NiceMock(); + ON_CALL(*mock, profileName).WillByDefault([&mock]() { + return "profile"; + }); + + const auto handle = (HANDLE)std::uintptr_t{4654}; + ON_CALL(*mock, startApplication) + .WillByDefault([handle](const auto& name, auto&&... args) { + return name == "valid.exe" ? handle : INVALID_HANDLE_VALUE; + }); + ON_CALL(*mock, waitForApplication) + .WillByDefault([&mock, original_handle = handle](HANDLE handle, bool, + LPDWORD exitCode) { + if (handle == original_handle) { + *exitCode = 0; + return true; + } + else { + *exitCode = static_cast(-1); + return false; + } }); - const auto handle = (HANDLE)std::uintptr_t{4654}; - EXPECT_CALL(*mock, startApplication(Eq("valid.exe"), _, _, _, _, _)) - .WillRepeatedly(Return(handle)); - EXPECT_CALL(*mock, startApplication(Eq("invalid.exe"), _, _, _, _, _)) - .WillRepeatedly(Return(INVALID_HANDLE_VALUE)); - ON_CALL(*mock, waitForApplication) - .WillByDefault([&mock, original_handle = handle](HANDLE handle, bool, - LPDWORD exitCode) { - if (handle == original_handle) { - *exitCode = 0; - return true; - } - else { - *exitCode = static_cast(-1); - return false; - } - }); - - return mock; - }, - py::return_value_policy::take_ownership); + + return mock; + }); }