From 31be918b0b2dd445bdf85d72a8eaa29841137bc8 Mon Sep 17 00:00:00 2001
From: Pierluigi Taddei <pierluigi.taddei@gmail.com>
Date: Thu, 8 Sep 2016 20:26:59 +0200
Subject: find_package: Optionally sort globbed directories in a meaningful
 order

Add `CMAKE_FIND_PACKAGE_SORT_{ORDER,DIRECTION}` variables to specify
sort order and direction.

When multiple package with the same name have been found in the same
location sorting option can be used to force a specific version to be
loaded (e.g. libA_1.12.0 instead of libA_1.1.0).  Currently sorting by
NAME and by NATURAL order have been implemented.

Natural ordering makes use of the `strverscmp(3)` ordering.
---
 Help/command/find_package.rst                      |  18 +++-
 Help/manual/cmake-variables.7.rst                  |   2 +
 Help/release/dev/find_package-dir-sort.rst         |  13 +++
 .../variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst |  16 +++
 Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst    |  36 +++++++
 Source/cmFindPackageCommand.cxx                    | 118 ++++++++++++++++++---
 Source/cmFindPackageCommand.h                      |  26 +++++
 Tests/CMakeLib/CMakeLists.txt                      |   1 +
 Tests/CMakeLib/testFindPackageCommand.cxx          |  76 +++++++++++++
 Tests/FindPackageTest/CMakeLists.txt               |  30 ++++++
 .../SortLib-3.1.1/SortLibConfig.cmake              |   2 +
 .../SortLib-3.1.1/SortLibConfigVersion.cmake       |   9 ++
 .../SortLib-3.10.1/SortLibConfig.cmake             |   2 +
 .../SortLib-3.10.1/SortLibConfigVersion.cmake      |   9 ++
 14 files changed, 341 insertions(+), 17 deletions(-)
 create mode 100644 Help/release/dev/find_package-dir-sort.rst
 create mode 100644 Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
 create mode 100644 Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
 create mode 100644 Tests/CMakeLib/testFindPackageCommand.cxx
 create mode 100644 Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake
 create mode 100644 Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake
 create mode 100644 Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake
 create mode 100644 Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake

diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index c44fe86..2cb1e5f 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -170,11 +170,21 @@ is acceptable the following variables are set:
 ``<package>_VERSION_COUNT``
   number of version components, 0 to 4
 
-and the corresponding package configuration file is loaded.  When
-multiple package configuration files are available whose version files
+and the corresponding package configuration file is loaded.
+When multiple package configuration files are available whose version files
 claim compatibility with the version requested it is unspecified which
-one is chosen.  No attempt is made to choose a highest or closest
-version number.
+one is chosen: unless the variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
+is set no attempt is made to choose a highest or closest version number.
+
+To control the order in which ``find_package`` checks for compatibiliy use
+the two variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and
+:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
+For instance in order to select the highest version one can set::
+
+  SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+  SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+
+before calling ``find_package``.
 
 Config mode provides an elaborate interface and search procedure.
 Much of the interface is provided for completeness and for use
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 74c9265..9e0efe9 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -38,6 +38,8 @@ Variables that Provide Information
    /variable/CMAKE_EXTRA_GENERATOR
    /variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
    /variable/CMAKE_FIND_PACKAGE_NAME
+   /variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION
+   /variable/CMAKE_FIND_PACKAGE_SORT_ORDER
    /variable/CMAKE_GENERATOR
    /variable/CMAKE_GENERATOR_PLATFORM
    /variable/CMAKE_GENERATOR_TOOLSET
diff --git a/Help/release/dev/find_package-dir-sort.rst b/Help/release/dev/find_package-dir-sort.rst
new file mode 100644
index 0000000..67b93eb
--- /dev/null
+++ b/Help/release/dev/find_package-dir-sort.rst
@@ -0,0 +1,13 @@
+find_package-dir-sort
+---------------------
+
+* The :command:`find_package` command gained the possibility of
+  sorting compatible libraries by ``NAME`` or by ``NATURAL`` sorting by
+  setting the two new variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
+  and :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
+
+* Variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` was added to control
+  the sorting mode of the :command:`find_package` command.
+
+* Variable :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` was added to control
+  the sorting direction the :command:`find_package` command.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
new file mode 100644
index 0000000..99e4ec1
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
@@ -0,0 +1,16 @@
+CMAKE_FIND_PACKAGE_SORT_DIRECTION
+---------------------------------
+
+The sorting direction used by :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`.
+It can assume one of the following values:
+
+``DEC``
+  Default.  Ordering is done in descending mode.
+  The highest folder found will be tested first.
+
+``ASC``
+  Ordering is done in ascending mode.
+  The lowest folder found will be tested first.
+
+If :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` is not set or is set to ``NONE``
+this variable has no effect.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
new file mode 100644
index 0000000..ba5f3a8
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
@@ -0,0 +1,36 @@
+CMAKE_FIND_PACKAGE_SORT_ORDER
+-----------------------------
+
+The default order for sorting packages found using :command:`find_package`.
+It can assume one of the following values:
+
+``NONE``
+  Default.  No attempt is done to sort packages.
+  The first valid package found will be selected.
+
+``NAME``
+  Sort packages lexicographically before selecting one.
+
+``NATURAL``
+  Sort packages using natural order (see ``strverscmp(3)`` manual),
+  i.e. such that contiguous digits are compared as whole numbers.
+
+Natural sorting can be employed to return the highest version when multiple
+versions of the same library are found by :command:`find_package`.  For
+example suppose that the following libraries have been found:
+
+* libX-1.1.0
+* libX-1.2.9
+* libX-1.2.10
+
+By setting ``NATURAL`` order we can select the one with the highest
+version number ``libX-1.2.10``.
+
+.. code-block:: cmake
+
+  set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+  find_package(libX CONFIG)
+
+The sort direction can be controlled using the
+:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable
+(by default decrescent, e.g. lib-B will be tested before lib-A).
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 8338c2a..72b5320 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -12,6 +12,7 @@
 #include "cmFindPackageCommand.h"
 
 #include "cmAlgorithms.h"
+#include <cmSystemTools.h>
 #include <cmsys/Directory.hxx>
 #include <cmsys/Encoding.hxx>
 #include <cmsys/RegularExpression.hxx>
@@ -33,6 +34,45 @@ cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::Builds(
 cmFindPackageCommand::PathLabel
   cmFindPackageCommand::PathLabel::SystemRegistry("SYSTEM_PACKAGE_REGISTRY");
 
+struct StrverscmpGreater
+{
+  bool operator()(const std::string& lhs, const std::string& rhs) const
+  {
+    return cmSystemTools::strverscmp(lhs, rhs) > 0;
+  }
+};
+
+struct StrverscmpLesser
+{
+  bool operator()(const std::string& lhs, const std::string& rhs) const
+  {
+    return cmSystemTools::strverscmp(lhs, rhs) < 0;
+  }
+};
+
+void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin,
+                                std::vector<std::string>::iterator end,
+                                SortOrderType order, SortDirectionType dir)
+{
+  if (order == Name_order) {
+    if (dir == Dec) {
+      std::sort(begin, end, std::greater<std::string>());
+    } else {
+      std::sort(begin, end);
+    }
+  } else if (order == Natural)
+  // natural order uses letters and numbers (contiguous numbers digit are
+  // compared such that e.g. 000  00 < 01 < 010 < 09 < 0 < 1 < 9 < 10
+  {
+    if (dir == Dec) {
+      std::sort(begin, end, StrverscmpGreater());
+    } else {
+      std::sort(begin, end, StrverscmpLesser());
+    }
+  }
+  // else do not sort
+}
+
 cmFindPackageCommand::cmFindPackageCommand()
 {
   this->CMakePathName = "PACKAGE";
@@ -58,7 +98,8 @@ cmFindPackageCommand::cmFindPackageCommand()
   this->VersionFoundTweak = 0;
   this->VersionFoundCount = 0;
   this->RequiredCMakeVersion = 0;
-
+  this->SortOrder = None;
+  this->SortDirection = Asc;
   this->AppendSearchPathGroups();
 }
 
@@ -135,6 +176,23 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
     this->NoSystemRegistry = true;
   }
 
+  // Check if Sorting should be enabled
+  if (const char* so =
+        this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_ORDER")) {
+
+    if (strcmp(so, "NAME") == 0) {
+      this->SortOrder = Name_order;
+    } else if (strcmp(so, "NATURAL") == 0) {
+      this->SortOrder = Natural;
+    } else {
+      this->SortOrder = None;
+    }
+  }
+  if (const char* sd =
+        this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_DIRECTION")) {
+    this->SortDirection = strcmp(sd, "ASC") == 0 ? Asc : Dec;
+  }
+
   // Find the current root path mode.
   this->SelectDefaultRootPathMode();
 
@@ -1666,17 +1724,33 @@ private:
 class cmFileListGeneratorProject : public cmFileListGeneratorBase
 {
 public:
-  cmFileListGeneratorProject(std::vector<std::string> const& names)
+  cmFileListGeneratorProject(std::vector<std::string> const& names,
+                             cmFindPackageCommand::SortOrderType so,
+                             cmFindPackageCommand::SortDirectionType sd)
     : cmFileListGeneratorBase()
     , Names(names)
   {
+    this->SetSort(so, sd);
   }
   cmFileListGeneratorProject(cmFileListGeneratorProject const& r)
     : cmFileListGeneratorBase()
     , Names(r.Names)
   {
+    this->SetSort(r.SortOrder, r.SortDirection);
+  }
+
+  void SetSort(cmFindPackageCommand::SortOrderType o,
+               cmFindPackageCommand::SortDirectionType d)
+  {
+    SortOrder = o;
+    SortDirection = d;
   }
 
+protected:
+  // sort parameters
+  cmFindPackageCommand::SortOrderType SortOrder;
+  cmFindPackageCommand::SortDirectionType SortDirection;
+
 private:
   std::vector<std::string> const& Names;
   bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE
@@ -1698,6 +1772,13 @@ private:
       }
     }
 
+    // before testing the matches check if there is a specific sorting order to
+    // perform
+    if (this->SortOrder != cmFindPackageCommand::None) {
+      cmFindPackageCommand::Sort(matches.begin(), matches.end(), SortOrder,
+                                 SortDirection);
+    }
+
     for (std::vector<std::string>::const_iterator i = matches.begin();
          i != matches.end(); ++i) {
       if (this->Consider(parent + *i, lister)) {
@@ -1895,7 +1976,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
   {
     cmFindPackageFileList lister(this);
     lister / cmFileListGeneratorFixed(prefix) /
-      cmFileListGeneratorProject(this->Names);
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection);
     if (lister.Search()) {
       return true;
     }
@@ -1905,7 +1987,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
   {
     cmFindPackageFileList lister(this);
     lister / cmFileListGeneratorFixed(prefix) /
-      cmFileListGeneratorProject(this->Names) /
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection) /
       cmFileListGeneratorCaseInsensitive("cmake");
     if (lister.Search()) {
       return true;
@@ -1932,7 +2015,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
     lister / cmFileListGeneratorFixed(prefix) /
       cmFileListGeneratorEnumerate(common) /
       cmFileListGeneratorFixed("cmake") /
-      cmFileListGeneratorProject(this->Names);
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection);
     if (lister.Search()) {
       return true;
     }
@@ -1943,7 +2027,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
     cmFindPackageFileList lister(this);
     lister / cmFileListGeneratorFixed(prefix) /
       cmFileListGeneratorEnumerate(common) /
-      cmFileListGeneratorProject(this->Names);
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection);
     if (lister.Search()) {
       return true;
     }
@@ -1954,7 +2039,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
     cmFindPackageFileList lister(this);
     lister / cmFileListGeneratorFixed(prefix) /
       cmFileListGeneratorEnumerate(common) /
-      cmFileListGeneratorProject(this->Names) /
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection) /
       cmFileListGeneratorCaseInsensitive("cmake");
     if (lister.Search()) {
       return true;
@@ -1965,10 +2051,12 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
   {
     cmFindPackageFileList lister(this);
     lister / cmFileListGeneratorFixed(prefix) /
-      cmFileListGeneratorProject(this->Names) /
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection) /
       cmFileListGeneratorEnumerate(common) /
       cmFileListGeneratorFixed("cmake") /
-      cmFileListGeneratorProject(this->Names);
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection);
     if (lister.Search()) {
       return true;
     }
@@ -1978,9 +2066,11 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
   {
     cmFindPackageFileList lister(this);
     lister / cmFileListGeneratorFixed(prefix) /
-      cmFileListGeneratorProject(this->Names) /
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection) /
       cmFileListGeneratorEnumerate(common) /
-      cmFileListGeneratorProject(this->Names);
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection);
     if (lister.Search()) {
       return true;
     }
@@ -1990,9 +2080,11 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
   {
     cmFindPackageFileList lister(this);
     lister / cmFileListGeneratorFixed(prefix) /
-      cmFileListGeneratorProject(this->Names) /
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection) /
       cmFileListGeneratorEnumerate(common) /
-      cmFileListGeneratorProject(this->Names) /
+      cmFileListGeneratorProject(this->Names, this->SortOrder,
+                                 this->SortDirection) /
       cmFileListGeneratorCaseInsensitive("cmake");
     if (lister.Search()) {
       return true;
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index 087107e..babdd5a 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -24,6 +24,27 @@ class cmFindPackageFileList;
 class cmFindPackageCommand : public cmFindCommon
 {
 public:
+  /*! A sorting order strategy to be applied to recovered package folders (see
+   * FIND_PACKAGE_SORT_ORDER)*/
+  enum /*class*/ SortOrderType
+  {
+    None,
+    Name_order,
+    Natural
+  };
+  /*! A sorting direction to be applied to recovered package folders (see
+   * FIND_PACKAGE_SORT_DIRECTION)*/
+  enum /*class*/ SortDirectionType
+  {
+    Asc,
+    Dec
+  };
+
+  /*! sorts a given list of string based on the input sort parameters */
+  static void Sort(std::vector<std::string>::iterator begin,
+                   std::vector<std::string>::iterator end, SortOrderType order,
+                   SortDirectionType dir);
+
   cmFindPackageCommand();
 
   /**
@@ -156,6 +177,11 @@ private:
   std::vector<std::string> Configs;
   std::set<std::string> IgnoredPaths;
 
+  /*! the selected sortOrder (None by default)*/
+  SortOrderType SortOrder;
+  /*! the selected sortDirection (Asc by default)*/
+  SortDirectionType SortDirection;
+
   struct ConfigFileInfo
   {
     std::string filename;
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index 7ef3c03..405917a 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -11,6 +11,7 @@ set(CMakeLib_TESTS
   testUTF8
   testXMLParser
   testXMLSafe
+  testFindPackageCommand
   )
 
 set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/Tests/CMakeLib/testFindPackageCommand.cxx b/Tests/CMakeLib/testFindPackageCommand.cxx
new file mode 100644
index 0000000..1cddb0e
--- /dev/null
+++ b/Tests/CMakeLib/testFindPackageCommand.cxx
@@ -0,0 +1,76 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmFindPackageCommand.h"
+
+#include <iostream>
+#include <string>
+
+#define cmPassed(m) std::cout << "Passed: " << (m) << "\n"
+#define cmFailed(m)                                                           \
+  std::cout << "FAILED: " << (m) << "\n";                                     \
+  failed = 1
+
+int testFindPackageCommand(int /*unused*/, char* /*unused*/ [])
+{
+  int failed = 0;
+
+  // ----------------------------------------------------------------------
+  // Test cmFindPackage::Sort
+  std::vector<std::string> testString;
+  testString.push_back("lib-0.0");
+  testString.push_back("lib-1.2");
+  testString.push_back("lib-2.0");
+  testString.push_back("lib-19.0.1");
+  testString.push_back("lib-20.01.1");
+  testString.push_back("lib-20.2.2a");
+
+  cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+                             cmFindPackageCommand::Natural,
+                             cmFindPackageCommand::Asc);
+  if (!(testString[0] == "lib-0.0" && testString[1] == "lib-1.2" &&
+        testString[2] == "lib-2.0" && testString[3] == "lib-19.0.1" &&
+        testString[4] == "lib-20.01.1" && testString[5] == "lib-20.2.2a")) {
+    cmFailed("cmSystemTools::Sort fail with Natural ASC");
+  }
+
+  cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+                             cmFindPackageCommand::Natural,
+                             cmFindPackageCommand::Dec);
+  if (!(testString[5] == "lib-0.0" && testString[4] == "lib-1.2" &&
+        testString[3] == "lib-2.0" && testString[2] == "lib-19.0.1" &&
+        testString[1] == "lib-20.01.1" && testString[0] == "lib-20.2.2a")) {
+    cmFailed("cmSystemTools::Sort fail with Natural ASC");
+  }
+
+  cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+                             cmFindPackageCommand::Name_order,
+                             cmFindPackageCommand::Dec);
+  if (!(testString[5] == "lib-0.0" && testString[4] == "lib-1.2" &&
+        testString[3] == "lib-19.0.1" && testString[2] == "lib-2.0" &&
+        testString[1] == "lib-20.01.1" && testString[0] == "lib-20.2.2a")) {
+    cmFailed("cmSystemTools::Sort fail with Name DEC");
+  }
+
+  cmFindPackageCommand::Sort(testString.begin(), testString.end(),
+                             cmFindPackageCommand::Name_order,
+                             cmFindPackageCommand::Asc);
+  if (!(testString[0] == "lib-0.0" && testString[1] == "lib-1.2" &&
+        testString[2] == "lib-19.0.1" && testString[3] == "lib-2.0" &&
+        testString[4] == "lib-20.01.1" && testString[5] == "lib-20.2.2a")) {
+    cmFailed("cmSystemTools::Sort fail with Natural ASC");
+  }
+
+  if (!failed) {
+    cmPassed("cmSystemTools::Sort working");
+  }
+  return failed;
+}
diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt
index 04bbbc6..1a6f204 100644
--- a/Tests/FindPackageTest/CMakeLists.txt
+++ b/Tests/FindPackageTest/CMakeLists.txt
@@ -633,3 +633,33 @@ endif()
 if(PACKAGE_VERSION_UNSUITABLE)
   message(SEND_ERROR "PACKAGE_VERSION_UNSUITABLE set, but must not be !")
 endif()
+
+
+############################################################################
+##Test FIND_PACKAGE using sorting
+set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
+
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.1.1")
+  message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Name Asc! ${SortLib_VERSION}")
+endif()
+unset(SortLib_VERSION)
+
+
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.10.1")
+  message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Natural! Dec ${SortLib_VERSION}")
+endif()
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+unset(SortLib_VERSION)
+
+
+unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
+unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
+set(CMAKE_PREFIX_PATH )
diff --git a/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake
new file mode 100644
index 0000000..c1f2088
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake
@@ -0,0 +1,2 @@
+set(SORT_LIB_VERSION 3.1.1)
+message("SortLib 3.1.1 config reached")
diff --git a/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake
new file mode 100644
index 0000000..fa927c7
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake
@@ -0,0 +1,9 @@
+set(PACKAGE_VERSION 3.1.1)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3)
+  if(PACKAGE_FIND_VERSION_MINOR EQUAL 1)
+    set(PACKAGE_VERSION_COMPATIBLE 1)
+    if(PACKAGE_FIND_VERSION_PATCH EQUAL 1)
+      set(PACKAGE_VERSION_EXACT 1)
+    endif()
+  endif()
+endif()
diff --git a/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake
new file mode 100644
index 0000000..3f3f659
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake
@@ -0,0 +1,2 @@
+set(SORT_LIB_VERSION 3.10.1)
+message("SortLib 3.10.1 config reached")
diff --git a/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake
new file mode 100644
index 0000000..6f44c2d
--- /dev/null
+++ b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake
@@ -0,0 +1,9 @@
+set(PACKAGE_VERSION 3.10.1)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3)
+  if(PACKAGE_FIND_VERSION_MINOR EQUAL 10)
+    set(PACKAGE_VERSION_COMPATIBLE 1)
+    if(PACKAGE_FIND_VERSION_PATCH EQUAL 1)
+      set(PACKAGE_VERSION_EXACT 1)
+    endif()
+  endif()
+endif()
-- 
cgit v0.12