diff --git a/libs/linglong/src/linglong/cli/cli_printer.cpp b/libs/linglong/src/linglong/cli/cli_printer.cpp index c4d209879..14d5f8a1c 100644 --- a/libs/linglong/src/linglong/cli/cli_printer.cpp +++ b/libs/linglong/src/linglong/cli/cli_printer.cpp @@ -121,12 +121,15 @@ void CLIPrinter::printSearchResult( return lhs.packageInfoV2Module < rhs.packageInfoV2Module; auto lhsVer = package::Version::parse(lhs.version.c_str()); + auto rhsVer = package::Version::parse(rhs.version.c_str()); + if (!lhsVer && !rhsVer) { + return lhs.version > rhs.version; + } if (!lhsVer) { return false; } - auto rhsVer = package::Version::parse(rhs.version.c_str()); if (!rhsVer) { - return false; + return true; } return *lhsVer > *rhsVer; diff --git a/libs/linglong/src/linglong/cli/json_printer.cpp b/libs/linglong/src/linglong/cli/json_printer.cpp index dd19ee7e0..ce9d54908 100644 --- a/libs/linglong/src/linglong/cli/json_printer.cpp +++ b/libs/linglong/src/linglong/cli/json_printer.cpp @@ -51,12 +51,15 @@ void JSONPrinter::printSearchResult( return lhs.packageInfoV2Module < rhs.packageInfoV2Module; auto lhsVer = package::Version::parse(lhs.version.c_str()); + auto rhsVer = package::Version::parse(rhs.version.c_str()); + if (!lhsVer && !rhsVer) { + return lhs.version > rhs.version; + } if (!lhsVer) { return false; } - auto rhsVer = package::Version::parse(rhs.version.c_str()); if (!rhsVer) { - return false; + return true; } return *lhsVer > *rhsVer; diff --git a/libs/linglong/tests/ll-tests/src/linglong/cli/cli_printer_test.cpp b/libs/linglong/tests/ll-tests/src/linglong/cli/cli_printer_test.cpp index 2e01174f2..e17b36038 100644 --- a/libs/linglong/tests/ll-tests/src/linglong/cli/cli_printer_test.cpp +++ b/libs/linglong/tests/ll-tests/src/linglong/cli/cli_printer_test.cpp @@ -128,6 +128,51 @@ TEST(CLIPrinter, PrintSearchResultSorts) EXPECT_LT(out.find("2.0.0"), out.find("1.0.0")); } +TEST(CLIPrinter, PrintSearchResultSortsInvalidVersionsLast) +{ + // Only versions which are empty or consist of dots alone fail + // package::Version::parse; any other string is accepted by the fallback + // parser, so use "" and "..." to exercise the unparsable path. + const std::map> searchResult{ + { "repo1", + { makePackage("org.deepin.sort", "ver1", "1.0.0", "stable", "binary", "sorted"), + makePackage("org.deepin.sort", "bad1", "", "stable", "binary", "sorted"), + makePackage("org.deepin.sort", "ver3", "3.0.0", "stable", "binary", "sorted"), + makePackage("org.deepin.sort", "ver2", "2.0.0", "stable", "binary", "sorted"), + makePackage("org.deepin.sort", "bad2", "...", "stable", "binary", "sorted") } } + }; + + std::string cliOut; + { + CaptureStdout capture; + linglong::cli::CLIPrinter printer; + printer.printSearchResult(searchResult); + cliOut = capture.str(); + } + + std::string jsonOut; + { + CaptureStdout capture; + linglong::cli::JSONPrinter printer; + printer.printSearchResult(searchResult); + jsonOut = capture.str(); + } + + // records with a parsable version come first, highest to lowest; the + // unparsable ones come last, ordered by raw version string ("..." > "") + auto assertSearchOrder = [](const std::string &out) { + const std::vector expectedOrder{ "ver3", "ver2", "ver1", "bad2", "bad1" }; + for (const auto &marker : expectedOrder) { + EXPECT_THAT(out, ::testing::HasSubstr(marker)); + } + for (std::size_t i = 1; i < expectedOrder.size(); ++i) { + EXPECT_LT(out.find(expectedOrder[i - 1]), out.find(expectedOrder[i])); + } + }; + assertSearchOrder(cliOut); + assertSearchOrder(jsonOut); +} + TEST(CLIPrinter, PrintPruneResultEmpty) { CaptureStdout capture;