From dca2347980862d803c182bb5898b5bfaca54aa62 Mon Sep 17 00:00:00 2001
From: Marc Chevrier <marc.chevrier@sap.com>
Date: Mon, 26 Mar 2018 14:32:12 +0200
Subject: list: Add TRANSFORM sub-command

Issue: #17823
---
 Help/command/list.rst                              |  73 +++
 Help/release/dev/list-transform.rst                |   5 +
 Source/cmListCommand.cxx                           | 556 +++++++++++++++++++++
 Source/cmListCommand.h                             |   1 +
 Tests/RunCMake/list/RunCMakeTest.cmake             |  41 ++
 .../list/TRANSFORM-APPEND-NoArguments-result.txt   |   1 +
 .../list/TRANSFORM-APPEND-NoArguments-stderr.txt   |   4 +
 .../list/TRANSFORM-APPEND-NoArguments.cmake        |   2 +
 .../TRANSFORM-APPEND-TooManyArguments-result.txt   |   1 +
 .../TRANSFORM-APPEND-TooManyArguments-stderr.txt   |   4 +
 .../list/TRANSFORM-APPEND-TooManyArguments.cmake   |   2 +
 Tests/RunCMake/list/TRANSFORM-APPEND.cmake         |  48 ++
 ...ANSFORM-GENEX_STRIP-TooManyArguments-result.txt |   1 +
 ...ANSFORM-GENEX_STRIP-TooManyArguments-stderr.txt |   4 +
 .../TRANSFORM-GENEX_STRIP-TooManyArguments.cmake   |   2 +
 Tests/RunCMake/list/TRANSFORM-GENEX_STRIP.cmake    |  49 ++
 .../list/TRANSFORM-InvalidAction-result.txt        |   1 +
 .../list/TRANSFORM-InvalidAction-stderr.txt        |   4 +
 Tests/RunCMake/list/TRANSFORM-InvalidAction.cmake  |   2 +
 Tests/RunCMake/list/TRANSFORM-NoAction-result.txt  |   1 +
 Tests/RunCMake/list/TRANSFORM-NoAction-stderr.txt  |   4 +
 Tests/RunCMake/list/TRANSFORM-NoAction.cmake       |   2 +
 ...M-Output-OUTPUT_VARIABLE-NoArguments-result.txt |   1 +
 ...M-Output-OUTPUT_VARIABLE-NoArguments-stderr.txt |   4 +
 ...NSFORM-Output-OUTPUT_VARIABLE-NoArguments.cmake |   2 +
 ...put-OUTPUT_VARIABLE-TooManyArguments-result.txt |   1 +
 ...put-OUTPUT_VARIABLE-TooManyArguments-stderr.txt |   4 +
 ...M-Output-OUTPUT_VARIABLE-TooManyArguments.cmake |   2 +
 .../list/TRANSFORM-PREPEND-NoArguments-result.txt  |   1 +
 .../list/TRANSFORM-PREPEND-NoArguments-stderr.txt  |   4 +
 .../list/TRANSFORM-PREPEND-NoArguments.cmake       |   2 +
 .../TRANSFORM-PREPEND-TooManyArguments-result.txt  |   1 +
 .../TRANSFORM-PREPEND-TooManyArguments-stderr.txt  |   4 +
 .../list/TRANSFORM-PREPEND-TooManyArguments.cmake  |   2 +
 Tests/RunCMake/list/TRANSFORM-PREPEND.cmake        |  48 ++
 .../list/TRANSFORM-REPLACE-InvalidRegex-result.txt |   1 +
 .../list/TRANSFORM-REPLACE-InvalidRegex-stderr.txt |   5 +
 .../list/TRANSFORM-REPLACE-InvalidRegex.cmake      |   2 +
 .../TRANSFORM-REPLACE-InvalidReplace-result.txt    |   1 +
 .../TRANSFORM-REPLACE-InvalidReplace1-result.txt   |   1 +
 .../TRANSFORM-REPLACE-InvalidReplace1-stderr.txt   |   5 +
 .../list/TRANSFORM-REPLACE-InvalidReplace1.cmake   |   2 +
 .../TRANSFORM-REPLACE-InvalidReplace2-result.txt   |   1 +
 .../TRANSFORM-REPLACE-InvalidReplace2-stderr.txt   |   5 +
 .../list/TRANSFORM-REPLACE-InvalidReplace2.cmake   |   2 +
 .../list/TRANSFORM-REPLACE-NoArguments-result.txt  |   1 +
 .../list/TRANSFORM-REPLACE-NoArguments-stderr.txt  |   4 +
 .../list/TRANSFORM-REPLACE-NoArguments.cmake       |   2 +
 .../TRANSFORM-REPLACE-NoEnoughArguments-result.txt |   1 +
 .../TRANSFORM-REPLACE-NoEnoughArguments-stderr.txt |   4 +
 .../list/TRANSFORM-REPLACE-NoEnoughArguments.cmake |   2 +
 .../TRANSFORM-REPLACE-TooManyArguments-result.txt  |   1 +
 .../TRANSFORM-REPLACE-TooManyArguments-stderr.txt  |   4 +
 .../list/TRANSFORM-REPLACE-TooManyArguments.cmake  |   2 +
 Tests/RunCMake/list/TRANSFORM-REPLACE.cmake        |  48 ++
 .../TRANSFORM-STRIP-TooManyArguments-result.txt    |   1 +
 .../TRANSFORM-STRIP-TooManyArguments-stderr.txt    |   4 +
 .../list/TRANSFORM-STRIP-TooManyArguments.cmake    |   2 +
 Tests/RunCMake/list/TRANSFORM-STRIP.cmake          |  49 ++
 .../TRANSFORM-Selector-AT-BadArgument-result.txt   |   1 +
 .../TRANSFORM-Selector-AT-BadArgument-stderr.txt   |   4 +
 .../list/TRANSFORM-Selector-AT-BadArgument.cmake   |   2 +
 .../TRANSFORM-Selector-AT-InvalidIndex-result.txt  |   1 +
 .../TRANSFORM-Selector-AT-InvalidIndex-stderr.txt  |   4 +
 .../list/TRANSFORM-Selector-AT-InvalidIndex.cmake  |   2 +
 .../TRANSFORM-Selector-AT-NoArguments-result.txt   |   1 +
 .../TRANSFORM-Selector-AT-NoArguments-stderr.txt   |   4 +
 .../list/TRANSFORM-Selector-AT-NoArguments.cmake   |   2 +
 .../TRANSFORM-Selector-FOR-BadArgument-result.txt  |   1 +
 .../TRANSFORM-Selector-FOR-BadArgument-stderr.txt  |   5 +
 .../list/TRANSFORM-Selector-FOR-BadArgument.cmake  |   2 +
 .../TRANSFORM-Selector-FOR-InvalidIndex-result.txt |   1 +
 .../TRANSFORM-Selector-FOR-InvalidIndex-stderr.txt |   4 +
 .../list/TRANSFORM-Selector-FOR-InvalidIndex.cmake |   2 +
 .../TRANSFORM-Selector-FOR-NoArguments-result.txt  |   1 +
 .../TRANSFORM-Selector-FOR-NoArguments-stderr.txt  |   4 +
 .../list/TRANSFORM-Selector-FOR-NoArguments.cmake  |   2 +
 ...SFORM-Selector-FOR-NoEnoughArguments-result.txt |   1 +
 ...SFORM-Selector-FOR-NoEnoughArguments-stderr.txt |   4 +
 .../TRANSFORM-Selector-FOR-NoEnoughArguments.cmake |   2 +
 ...NSFORM-Selector-FOR-TooManyArguments-result.txt |   1 +
 ...NSFORM-Selector-FOR-TooManyArguments-stderr.txt |   4 +
 .../TRANSFORM-Selector-FOR-TooManyArguments.cmake  |   2 +
 ...RANSFORM-Selector-REGEX-InvalidRegex-result.txt |   1 +
 ...RANSFORM-Selector-REGEX-InvalidRegex-stderr.txt |   5 +
 .../TRANSFORM-Selector-REGEX-InvalidRegex.cmake    |   2 +
 ...TRANSFORM-Selector-REGEX-NoArguments-result.txt |   1 +
 ...TRANSFORM-Selector-REGEX-NoArguments-stderr.txt |   5 +
 .../TRANSFORM-Selector-REGEX-NoArguments.cmake     |   2 +
 ...FORM-Selector-REGEX-TooManyArguments-result.txt |   1 +
 ...FORM-Selector-REGEX-TooManyArguments-stderr.txt |   4 +
 ...TRANSFORM-Selector-REGEX-TooManyArguments.cmake |   2 +
 .../TRANSFORM-TOLOWER-TooManyArguments-result.txt  |   1 +
 .../TRANSFORM-TOLOWER-TooManyArguments-stderr.txt  |   4 +
 .../list/TRANSFORM-TOLOWER-TooManyArguments.cmake  |   2 +
 Tests/RunCMake/list/TRANSFORM-TOLOWER.cmake        |  48 ++
 .../TRANSFORM-TOUPPER-TooManyArguments-result.txt  |   1 +
 .../TRANSFORM-TOUPPER-TooManyArguments-stderr.txt  |   4 +
 .../list/TRANSFORM-TOUPPER-TooManyArguments.cmake  |   2 +
 Tests/RunCMake/list/TRANSFORM-TOUPPER.cmake        |  48 ++
 100 files changed, 1224 insertions(+)
 create mode 100644 Help/release/dev/list-transform.rst
 create mode 100644 Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-APPEND.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-GENEX_STRIP.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-InvalidAction-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-InvalidAction-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-InvalidAction.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-NoAction-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-NoAction-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-NoAction.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-PREPEND.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-REPLACE.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-STRIP.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOLOWER.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-result.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments.cmake
 create mode 100644 Tests/RunCMake/list/TRANSFORM-TOUPPER.cmake

diff --git a/Help/command/list.rst b/Help/command/list.rst
index 6218a2a..9451d31 100644
--- a/Help/command/list.rst
+++ b/Help/command/list.rst
@@ -151,6 +151,79 @@ REMOVE_DUPLICATES
 
 Removes duplicated items in the list.
 
+TRANSFORM
+"""""""""
+
+::
+
+  list(TRANSFORM <list> <ACTION> [<SELECTOR>]
+                        [OUTPUT_VARIABLE <output variable>])
+
+Transforms the list by applying an action to all or, by specifying a
+``<SELECTOR>``, to the selected elements of the list, storing result in-place
+or in the specified output variable.
+
+.. note::
+
+   ``TRANSFORM`` sub-command does not change the number of elements of the
+   list. If a ``<SELECTOR>`` is specified, only some elements will be changed,
+   the other ones will remain same as before the transformation.
+
+``<ACTION>`` specify the action to apply to the elements of list.
+The actions have exactly the same semantics as sub-commands of
+:command:`string` command.
+
+The ``<ACTION>`` may be one of:
+
+``APPEND``, ``PREPEND``: Append, prepend specified value to each element of
+the list. ::
+
+  list(TRANSFORM <list> <APPEND|PREPEND> <value> ...)
+
+``TOUPPER``, ``TOLOWER``: Convert each element of the list to upper, lower
+characters. ::
+
+  list(TRANSFORM <list> <TOLOWER|TOUPPER> ...)
+
+``STRIP``: Remove leading and trailing spaces from each element of the
+list. ::
+
+  list(TRANSFORM <list> STRIP ...)
+
+``GENEX_STRIP``: Strip any
+:manual:`generator expressions <cmake-generator-expressions(7)>` from each
+element of the list. ::
+
+  list(TRANSFORM <list> GENEX_STRIP ...)
+
+``REPLACE``: Match the regular expression as many times as possible and
+substitute the replacement expression for the match for each element
+of the list
+(Same semantic as ``REGEX REPLACE`` from :command:`string` command). ::
+
+  list(TRANSFORM <list> REPLACE <regular_expression>
+                                <replace_expression> ...)
+
+``<SELECTOR>`` select which elements of the list will be transformed. Only one
+type of selector can be specified at a time.
+
+The ``<SELECTOR>`` may be one of:
+
+``AT``: Specify a list of indexes. ::
+
+  list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...)
+
+``FOR``: Specify a range with, optionaly, an incerment used to iterate over
+the range. ::
+
+  list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...)
+
+``REGEX``: Specify a regular expression. Only elements matching the regular
+expression will be transformed. ::
+
+  list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...)
+
+
 Sorting
 ^^^^^^^
 
diff --git a/Help/release/dev/list-transform.rst b/Help/release/dev/list-transform.rst
new file mode 100644
index 0000000..4a6dacc
--- /dev/null
+++ b/Help/release/dev/list-transform.rst
@@ -0,0 +1,5 @@
+list-transform
+--------------
+
+* The :command:`list` command learned a ``TRANSFORM`` sub-command
+  to apply various string transformation to list's elements.
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 821e6d1..31bc1c0 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -5,14 +5,19 @@
 #include "cmsys/RegularExpression.hxx"
 #include <algorithm>
 #include <assert.h>
+#include <functional>
 #include <iterator>
+#include <set>
 #include <sstream>
+#include <stdexcept>
 #include <stdio.h>
 #include <stdlib.h> // required for atoi
 
 #include "cmAlgorithms.h"
+#include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
+#include "cmStringReplaceHelper.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -54,6 +59,9 @@ bool cmListCommand::InitialPass(std::vector<std::string> const& args,
   if (subCommand == "REMOVE_DUPLICATES") {
     return this->HandleRemoveDuplicatesCommand(args);
   }
+  if (subCommand == "TRANSFORM") {
+    return this->HandleTransformCommand(args);
+  }
   if (subCommand == "SORT") {
     return this->HandleSortCommand(args);
   }
@@ -407,6 +415,554 @@ bool cmListCommand::HandleRemoveDuplicatesCommand(
   return true;
 }
 
+// Helpers for list(TRANSFORM <list> ...)
+namespace {
+using transform_type = std::function<std::string(const std::string&)>;
+
+class transform_error : public std::runtime_error
+{
+public:
+  transform_error(const std::string& error)
+    : std::runtime_error(error)
+  {
+  }
+};
+
+class TransformSelector
+{
+public:
+  virtual ~TransformSelector() {}
+
+  std::string Tag;
+
+  virtual bool Validate(std::size_t count = 0) = 0;
+
+  virtual bool InSelection(const std::string&) = 0;
+
+  virtual void Transform(std::vector<std::string>& list,
+                         const transform_type& transform)
+  {
+    std::transform(list.begin(), list.end(), list.begin(), transform);
+  }
+
+protected:
+  TransformSelector(std::string&& tag)
+    : Tag(std::move(tag))
+  {
+  }
+};
+class TransformNoSelector : public TransformSelector
+{
+public:
+  TransformNoSelector()
+    : TransformSelector("NO SELECTOR")
+  {
+  }
+
+  bool Validate(std::size_t) override { return true; }
+
+  bool InSelection(const std::string&) override { return true; }
+};
+class TransformSelectorRegex : public TransformSelector
+{
+public:
+  TransformSelectorRegex(const std::string& regex)
+    : TransformSelector("REGEX")
+    , Regex(regex)
+  {
+  }
+
+  bool Validate(std::size_t) override { return this->Regex.is_valid(); }
+
+  bool InSelection(const std::string& value) override
+  {
+    return this->Regex.find(value);
+  }
+
+  cmsys::RegularExpression Regex;
+};
+class TransformSelectorIndexes : public TransformSelector
+{
+public:
+  std::vector<int> Indexes;
+
+  bool InSelection(const std::string&) override { return true; }
+
+  void Transform(std::vector<std::string>& list,
+                 const transform_type& transform) override
+  {
+    this->Validate(list.size());
+
+    for (auto index : this->Indexes) {
+      list[index] = transform(list[index]);
+    }
+  }
+
+protected:
+  TransformSelectorIndexes(std::string&& tag)
+    : TransformSelector(std::move(tag))
+  {
+  }
+  TransformSelectorIndexes(std::string&& tag, std::vector<int>&& indexes)
+    : TransformSelector(std::move(tag))
+    , Indexes(indexes)
+  {
+  }
+
+  int NormalizeIndex(int index, std::size_t count)
+  {
+    if (index < 0) {
+      index = static_cast<int>(count) + index;
+    }
+    if (index < 0 || count <= static_cast<std::size_t>(index)) {
+      std::ostringstream str;
+      str << "sub-command TRANSFORM, selector " << this->Tag
+          << ", index: " << index << " out of range (-" << count << ", "
+          << count - 1 << ").";
+      throw transform_error(str.str());
+    }
+    return index;
+  }
+};
+class TransformSelectorAt : public TransformSelectorIndexes
+{
+public:
+  TransformSelectorAt(std::vector<int>&& indexes)
+    : TransformSelectorIndexes("AT", std::move(indexes))
+  {
+  }
+
+  bool Validate(std::size_t count) override
+  {
+    decltype(Indexes) indexes;
+
+    for (auto index : Indexes) {
+      indexes.push_back(this->NormalizeIndex(index, count));
+    }
+    this->Indexes = std::move(indexes);
+
+    return true;
+  }
+};
+class TransformSelectorFor : public TransformSelectorIndexes
+{
+public:
+  TransformSelectorFor(int start, int stop, int step)
+    : TransformSelectorIndexes("FOR")
+    , Start(start)
+    , Stop(stop)
+    , Step(step)
+  {
+  }
+
+  bool Validate(std::size_t count) override
+  {
+    this->Start = this->NormalizeIndex(this->Start, count);
+    this->Stop = this->NormalizeIndex(this->Stop, count);
+
+    // compute indexes
+    auto size = (this->Stop - this->Start + 1) / this->Step;
+    if ((this->Stop - this->Start + 1) % this->Step != 0) {
+      size += 1;
+    }
+
+    this->Indexes.resize(size);
+    auto start = this->Start, step = this->Step;
+    std::generate(this->Indexes.begin(), this->Indexes.end(),
+                  [&start, step]() -> int {
+                    auto r = start;
+                    start += step;
+                    return r;
+                  });
+
+    return true;
+  }
+
+private:
+  int Start, Stop, Step;
+};
+
+class TransformAction
+{
+public:
+  virtual ~TransformAction() {}
+
+  virtual std::string Transform(const std::string& input) = 0;
+};
+class TransformReplace : public TransformAction
+{
+public:
+  TransformReplace(const std::vector<std::string>& arguments,
+                   cmMakefile* makefile)
+    : ReplaceHelper(arguments[0], arguments[1], makefile)
+  {
+    makefile->ClearMatches();
+
+    if (!this->ReplaceHelper.IsRegularExpressionValid()) {
+      std::ostringstream error;
+      error
+        << "sub-command TRANSFORM, action REPLACE: Failed to compile regex \""
+        << arguments[0] << "\".";
+      throw transform_error(error.str());
+    }
+    if (!this->ReplaceHelper.IsReplaceExpressionValid()) {
+      std::ostringstream error;
+      error << "sub-command TRANSFORM, action REPLACE: "
+            << this->ReplaceHelper.GetError() << ".";
+      throw transform_error(error.str());
+    }
+  }
+
+  std::string Transform(const std::string& input) override
+  {
+    // Scan through the input for all matches.
+    std::string output;
+
+    if (!this->ReplaceHelper.Replace(input, output)) {
+      std::ostringstream error;
+      error << "sub-command TRANSFORM, action REPLACE: "
+            << this->ReplaceHelper.GetError() << ".";
+      throw transform_error(error.str());
+    }
+
+    return output;
+  }
+
+private:
+  cmStringReplaceHelper ReplaceHelper;
+};
+}
+
+bool cmListCommand::HandleTransformCommand(
+  std::vector<std::string> const& args)
+{
+  if (args.size() < 3) {
+    this->SetError(
+      "sub-command TRANSFORM requires an action to be specified.");
+    return false;
+  }
+
+  // Structure collecting all elements of the command
+  struct Command
+  {
+    Command(const std::string& listName)
+      : ListName(listName)
+      , OutputName(listName)
+    {
+    }
+
+    std::string Name;
+    std::string ListName;
+    std::vector<std::string> Arguments;
+    std::unique_ptr<TransformAction> Action;
+    std::unique_ptr<TransformSelector> Selector;
+    std::string OutputName;
+  } command(args[1]);
+
+  // Descriptor of action
+  // Arity: number of arguments required for the action
+  // Transform: lambda function implementing the action
+  struct ActionDescriptor
+  {
+    ActionDescriptor(const std::string& name)
+      : Name(name)
+    {
+    }
+    ActionDescriptor(const std::string& name, int arity,
+                     const transform_type& transform)
+      : Name(name)
+      , Arity(arity)
+      , Transform(transform)
+    {
+    }
+
+    operator const std::string&() const { return Name; }
+
+    std::string Name;
+    int Arity = 0;
+    transform_type Transform;
+  };
+
+  // Build a set of supported actions.
+  std::set<ActionDescriptor,
+           std::function<bool(const std::string&, const std::string&)>>
+  descriptors(
+    [](const std::string& x, const std::string& y) { return x < y; });
+  descriptors = { { "APPEND", 1,
+                    [&command](const std::string& s) -> std::string {
+                      if (command.Selector->InSelection(s)) {
+                        return s + command.Arguments[0];
+                      }
+
+                      return s;
+                    } },
+                  { "PREPEND", 1,
+                    [&command](const std::string& s) -> std::string {
+                      if (command.Selector->InSelection(s)) {
+                        return command.Arguments[0] + s;
+                      }
+
+                      return s;
+                    } },
+                  { "TOUPPER", 0,
+                    [&command](const std::string& s) -> std::string {
+                      if (command.Selector->InSelection(s)) {
+                        return cmSystemTools::UpperCase(s);
+                      }
+
+                      return s;
+                    } },
+                  { "TOLOWER", 0,
+                    [&command](const std::string& s) -> std::string {
+                      if (command.Selector->InSelection(s)) {
+                        return cmSystemTools::LowerCase(s);
+                      }
+
+                      return s;
+                    } },
+                  { "STRIP", 0,
+                    [&command](const std::string& s) -> std::string {
+                      if (command.Selector->InSelection(s)) {
+                        return cmSystemTools::TrimWhitespace(s);
+                      }
+
+                      return s;
+                    } },
+                  { "GENEX_STRIP", 0,
+                    [&command](const std::string& s) -> std::string {
+                      if (command.Selector->InSelection(s)) {
+                        return cmGeneratorExpression::Preprocess(
+                          s,
+                          cmGeneratorExpression::StripAllGeneratorExpressions);
+                      }
+
+                      return s;
+                    } },
+                  { "REPLACE", 2,
+                    [&command](const std::string& s) -> std::string {
+                      if (command.Selector->InSelection(s)) {
+                        return command.Action->Transform(s);
+                      }
+
+                      return s;
+                    } } };
+
+  using size_type = std::vector<std::string>::size_type;
+  size_type index = 2;
+
+  // Parse all possible function parameters
+  auto descriptor = descriptors.find(args[index]);
+
+  if (descriptor == descriptors.end()) {
+    std::ostringstream error;
+    error << " sub-command TRANSFORM, " << args[index] << " invalid action.";
+    this->SetError(error.str());
+    return false;
+  }
+
+  // Action arguments
+  index += 1;
+  if (args.size() < index + descriptor->Arity) {
+    std::ostringstream error;
+    error << "sub-command TRANSFORM, action " << descriptor->Name
+          << " expects " << descriptor->Arity << " argument(s).";
+    this->SetError(error.str());
+    return false;
+  }
+
+  command.Name = descriptor->Name;
+  index += descriptor->Arity;
+  if (descriptor->Arity > 0) {
+    command.Arguments =
+      std::vector<std::string>(args.begin() + 3, args.begin() + index);
+  }
+
+  if (command.Name == "REPLACE") {
+    try {
+      command.Action =
+        cm::make_unique<TransformReplace>(command.Arguments, this->Makefile);
+    } catch (const transform_error& e) {
+      this->SetError(e.what());
+      return false;
+    }
+  }
+
+  const std::string REGEX{ "REGEX" }, AT{ "AT" }, FOR{ "FOR" },
+    OUTPUT_VARIABLE{ "OUTPUT_VARIABLE" };
+
+  // handle optional arguments
+  while (args.size() > index) {
+    if ((args[index] == REGEX || args[index] == AT || args[index] == FOR) &&
+        command.Selector) {
+      std::ostringstream error;
+      error << "sub-command TRANSFORM, selector already specified ("
+            << command.Selector->Tag << ").";
+      this->SetError(error.str());
+      return false;
+    }
+
+    // REGEX selector
+    if (args[index] == REGEX) {
+      if (args.size() == ++index) {
+        this->SetError("sub-command TRANSFORM, selector REGEX expects "
+                       "'regular expression' argument.");
+        return false;
+      }
+
+      command.Selector = cm::make_unique<TransformSelectorRegex>(args[index]);
+      if (!command.Selector->Validate()) {
+        std::ostringstream error;
+        error << "sub-command TRANSFORM, selector REGEX failed to compile "
+                 "regex \"";
+        error << args[index] << "\".";
+        this->SetError(error.str());
+        return false;
+      }
+
+      index += 1;
+      continue;
+    }
+
+    // AT selector
+    if (args[index] == AT) {
+      // get all specified indexes
+      std::vector<int> indexes;
+      while (args.size() > ++index) {
+        std::size_t pos;
+        int value;
+
+        try {
+          value = std::stoi(args[index], &pos);
+          if (pos != args[index].length()) {
+            // this is not a number, stop processing
+            break;
+          }
+          indexes.push_back(value);
+        } catch (const std::invalid_argument&) {
+          // this is not a number, stop processing
+          break;
+        }
+      }
+
+      if (indexes.empty()) {
+        this->SetError(
+          "sub-command TRANSFORM, selector AT expects at least one "
+          "numeric value.");
+        return false;
+      }
+
+      command.Selector =
+        cm::make_unique<TransformSelectorAt>(std::move(indexes));
+
+      continue;
+    }
+
+    // FOR selector
+    if (args[index] == FOR) {
+      if (args.size() <= ++index + 1) {
+        this->SetError("sub-command TRANSFORM, selector FOR expects, at least,"
+                       " two arguments.");
+        return false;
+      }
+
+      int start = 0, stop = 0, step = 1;
+      bool valid = true;
+      try {
+        std::size_t pos;
+
+        start = std::stoi(args[index], &pos);
+        if (pos != args[index].length()) {
+          // this is not a number
+          valid = false;
+        } else {
+          stop = std::stoi(args[++index], &pos);
+          if (pos != args[index].length()) {
+            // this is not a number
+            valid = false;
+          }
+        }
+      } catch (const std::invalid_argument&) {
+        // this is not numbers
+        valid = false;
+      }
+      if (!valid) {
+        this->SetError("sub-command TRANSFORM, selector FOR expects, "
+                       "at least, two numeric values.");
+        return false;
+      }
+      // try to read a third numeric value for step
+      if (args.size() > ++index) {
+        try {
+          std::size_t pos;
+
+          step = std::stoi(args[index], &pos);
+          if (pos != args[index].length()) {
+            // this is not a number
+            step = 1;
+          } else {
+            index += 1;
+          }
+        } catch (const std::invalid_argument&) {
+          // this is not number, ignore exception
+        }
+      }
+
+      if (step < 0) {
+        this->SetError("sub-command TRANSFORM, selector FOR expects "
+                       "non negative numeric value for <step>.");
+      }
+
+      command.Selector =
+        cm::make_unique<TransformSelectorFor>(start, stop, step);
+
+      continue;
+    }
+
+    // output variable
+    if (args[index] == OUTPUT_VARIABLE) {
+      if (args.size() == ++index) {
+        this->SetError("sub-command TRANSFORM, OUTPUT_VARIABLE "
+                       "expects variable name argument.");
+        return false;
+      }
+
+      command.OutputName = args[index++];
+      continue;
+    }
+
+    std::ostringstream error;
+    error << "sub-command TRANSFORM, '"
+          << cmJoin(cmMakeRange(args).advance(index), " ")
+          << "': unexpected argument(s).";
+    this->SetError(error.str());
+    return false;
+  }
+
+  // expand the list variable
+  std::vector<std::string> varArgsExpanded;
+  if (!this->GetList(varArgsExpanded, command.ListName)) {
+    this->Makefile->AddDefinition(command.OutputName, "");
+    return true;
+  }
+
+  if (!command.Selector) {
+    // no selector specified, apply transformation to all elements
+    command.Selector = cm::make_unique<TransformNoSelector>();
+  }
+
+  try {
+    command.Selector->Transform(varArgsExpanded, descriptor->Transform);
+  } catch (const transform_error& e) {
+    this->SetError(e.what());
+    return false;
+  }
+
+  this->Makefile->AddDefinition(command.OutputName,
+                                cmJoin(varArgsExpanded, ";").c_str());
+
+  return true;
+}
+
 bool cmListCommand::HandleSortCommand(std::vector<std::string> const& args)
 {
   assert(args.size() >= 2);
diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h
index d69d8f9..76a9856 100644
--- a/Source/cmListCommand.h
+++ b/Source/cmListCommand.h
@@ -41,6 +41,7 @@ protected:
   bool HandleRemoveAtCommand(std::vector<std::string> const& args);
   bool HandleRemoveItemCommand(std::vector<std::string> const& args);
   bool HandleRemoveDuplicatesCommand(std::vector<std::string> const& args);
+  bool HandleTransformCommand(std::vector<std::string> const& args);
   bool HandleSortCommand(std::vector<std::string> const& args);
   bool HandleSublistCommand(std::vector<std::string> const& args);
   bool HandleReverseCommand(std::vector<std::string> const& args);
diff --git a/Tests/RunCMake/list/RunCMakeTest.cmake b/Tests/RunCMake/list/RunCMakeTest.cmake
index 3913783..bdc23a4 100644
--- a/Tests/RunCMake/list/RunCMakeTest.cmake
+++ b/Tests/RunCMake/list/RunCMakeTest.cmake
@@ -43,3 +43,44 @@ run_cmake(SUBLIST-NoArguments)
 run_cmake(SUBLIST-NoVariable)
 run_cmake(SUBLIST-InvalidLength)
 run_cmake(SUBLIST)
+
+run_cmake(TRANSFORM-NoAction)
+run_cmake(TRANSFORM-InvalidAction)
+# 'action' oriented tests
+run_cmake(TRANSFORM-TOUPPER-TooManyArguments)
+run_cmake(TRANSFORM-TOLOWER-TooManyArguments)
+run_cmake(TRANSFORM-STRIP-TooManyArguments)
+run_cmake(TRANSFORM-GENEX_STRIP-TooManyArguments)
+run_cmake(TRANSFORM-APPEND-NoArguments)
+run_cmake(TRANSFORM-APPEND-TooManyArguments)
+run_cmake(TRANSFORM-PREPEND-NoArguments)
+run_cmake(TRANSFORM-PREPEND-TooManyArguments)
+run_cmake(TRANSFORM-REPLACE-NoArguments)
+run_cmake(TRANSFORM-REPLACE-NoEnoughArguments)
+run_cmake(TRANSFORM-REPLACE-TooManyArguments)
+run_cmake(TRANSFORM-REPLACE-InvalidRegex)
+run_cmake(TRANSFORM-REPLACE-InvalidReplace1)
+run_cmake(TRANSFORM-REPLACE-InvalidReplace2)
+# 'selector' oriented tests
+run_cmake(TRANSFORM-Selector-REGEX-NoArguments)
+run_cmake(TRANSFORM-Selector-REGEX-TooManyArguments)
+run_cmake(TRANSFORM-Selector-REGEX-InvalidRegex)
+run_cmake(TRANSFORM-Selector-AT-NoArguments)
+run_cmake(TRANSFORM-Selector-AT-BadArgument)
+run_cmake(TRANSFORM-Selector-AT-InvalidIndex)
+run_cmake(TRANSFORM-Selector-FOR-NoArguments)
+run_cmake(TRANSFORM-Selector-FOR-NoEnoughArguments)
+run_cmake(TRANSFORM-Selector-FOR-TooManyArguments)
+run_cmake(TRANSFORM-Selector-FOR-BadArgument)
+run_cmake(TRANSFORM-Selector-FOR-InvalidIndex)
+# 'output' oriented tests
+run_cmake(TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments)
+run_cmake(TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments)
+# Successful tests
+run_cmake(TRANSFORM-TOUPPER)
+run_cmake(TRANSFORM-TOLOWER)
+run_cmake(TRANSFORM-STRIP)
+run_cmake(TRANSFORM-GENEX_STRIP)
+run_cmake(TRANSFORM-APPEND)
+run_cmake(TRANSFORM-PREPEND)
+run_cmake(TRANSFORM-REPLACE)
diff --git a/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-stderr.txt
new file mode 100644
index 0000000..028f8d5
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-APPEND-NoArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, action APPEND expects 1 argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments.cmake b/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments.cmake
new file mode 100644
index 0000000..f161187
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-APPEND-NoArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist APPEND)
diff --git a/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..aeb646d
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-APPEND-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments.cmake
new file mode 100644
index 0000000..8430a4c
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-APPEND-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist APPEND delta one_too_many)
diff --git a/Tests/RunCMake/list/TRANSFORM-APPEND.cmake b/Tests/RunCMake/list/TRANSFORM-APPEND.cmake
new file mode 100644
index 0000000..9639088
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-APPEND.cmake
@@ -0,0 +1,48 @@
+set(mylist alpha bravo charlie delta)
+
+list(TRANSFORM mylist APPEND "_A" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha_A;bravo_A;charlie_A;delta_A")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${output}\", expected is \"alpha_A;bravo_A;charlie_A;delta_A\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist APPEND "_A" AT 1 3 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo_A;charlie;delta_A")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${output}\", expected is \"alpha;bravo_A;charlie;delta_A\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist APPEND "_A" AT 1 -2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo_A;charlie_A;delta")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${output}\", expected is \"alpha;bravo_A;charlie_A;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist APPEND "_A" FOR 1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo_A;charlie_A;delta")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${output}\", expected is \"alpha;bravo_A;charlie_A;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist APPEND "_A" FOR 1 -1 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo_A;charlie_A;delta_A")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${output}\", expected is \"alpha;bravo_A;charlie_A;delta_A\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist APPEND "_A" FOR 0 -1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha_A;bravo;charlie_A;delta")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${output}\", expected is \"alpha_A;bravo;charlie_A;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist APPEND "_A" REGEX "(r|t)a" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo_A;charlie;delta_A")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${output}\", expected is \"alpha;bravo_A;charlie;delta_A\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist APPEND "_A" REGEX "(r|t)a")
+if (NOT mylist STREQUAL "alpha;bravo_A;charlie;delta_A")
+  message (FATAL_ERROR "TRANSFORM(APPEND) is \"${mylist}\", expected is \"alpha;bravo_A;charlie;delta_A\"")
+endif()
diff --git a/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..6071a00
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-GENEX_STRIP-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments.cmake
new file mode 100644
index 0000000..257d7fe
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist GENEX_STRIP one_too_many)
diff --git a/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP.cmake b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP.cmake
new file mode 100644
index 0000000..8045eef
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-GENEX_STRIP.cmake
@@ -0,0 +1,49 @@
+set(mylist one "$<1:two\;three>" four "$<TARGET_OBJECTS:some_target>")
+
+list(TRANSFORM mylist GENEX_STRIP OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "one;;four;")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${output}\", expected is \"one;;four;\"")
+endif()
+
+set(mylist "one $<CONFIG>" "$<1:two\;three>-$<PLATFORM_ID>" "$<ANGLE-R>four" "$<TARGET_OBJECTS:some_target>")
+unset(output)
+list(TRANSFORM mylist GENEX_STRIP AT 1 3 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "one $<CONFIG>;-;$<ANGLE-R>four;")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${output}\", expected is \"one $<CONFIG>;-;$<ANGLE-R>four;\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist GENEX_STRIP AT 1 -2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "one $<CONFIG>;-;four;$<TARGET_OBJECTS:some_target>")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${output}\", expected is \"one $<CONFIG>;-;four;$<TARGET_OBJECTS:some_target>\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist GENEX_STRIP FOR 1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "one $<CONFIG>;-;four;$<TARGET_OBJECTS:some_target>")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${output}\", expected is \"one $<CONFIG>;-;four;$<TARGET_OBJECTS:some_target>\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist GENEX_STRIP FOR 1 -1 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "one $<CONFIG>;-;four;")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${output}\", expected is \"one $<CONFIG>;-;four;\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist GENEX_STRIP FOR 0 -1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "one ;$<1:two;three>-$<PLATFORM_ID>;four;$<TARGET_OBJECTS:some_target>")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${output}\", expected is \"one ;$<1:two;three>-$<PLATFORM_ID>;four;$<TARGET_OBJECTS:some_target>\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist GENEX_STRIP REGEX "(D|G)>" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "one ;-;$<ANGLE-R>four;$<TARGET_OBJECTS:some_target>")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${output}\", expected is \"one ;-;$<ANGLE-R>four;$<TARGET_OBJECTS:some_target>\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist GENEX_STRIP REGEX "(D|G)>")
+if (NOT mylist STREQUAL "one ;-;$<ANGLE-R>four;$<TARGET_OBJECTS:some_target>")
+  message (FATAL_ERROR "TRANSFORM(GENEX_STRIP) is \"${mylist}\", expected is \"one ;-;$<ANGLE-R>four;$<TARGET_OBJECTS:some_target>\"")
+endif()
diff --git a/Tests/RunCMake/list/TRANSFORM-InvalidAction-result.txt b/Tests/RunCMake/list/TRANSFORM-InvalidAction-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-InvalidAction-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-InvalidAction-stderr.txt b/Tests/RunCMake/list/TRANSFORM-InvalidAction-stderr.txt
new file mode 100644
index 0000000..0fa45c9
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-InvalidAction-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-InvalidAction.cmake:2 \(list\):
+  list sub-command TRANSFORM, BAD_ACTION invalid action.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-InvalidAction.cmake b/Tests/RunCMake/list/TRANSFORM-InvalidAction.cmake
new file mode 100644
index 0000000..fb2cc30
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-InvalidAction.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist BAD_ACTION)
diff --git a/Tests/RunCMake/list/TRANSFORM-NoAction-result.txt b/Tests/RunCMake/list/TRANSFORM-NoAction-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-NoAction-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-NoAction-stderr.txt b/Tests/RunCMake/list/TRANSFORM-NoAction-stderr.txt
new file mode 100644
index 0000000..68e9e9d
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-NoAction-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-NoAction.cmake:2 \(list\):
+  list sub-command TRANSFORM requires an action to be specified.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-NoAction.cmake b/Tests/RunCMake/list/TRANSFORM-NoAction.cmake
new file mode 100644
index 0000000..3690f14
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-NoAction.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist)
diff --git a/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-stderr.txt
new file mode 100644
index 0000000..b4f4e06
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, OUTPUT_VARIABLE expects variable name argument.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments.cmake
new file mode 100644
index 0000000..acc4094
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-NoArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER OUTPUT_VARIABLE)
diff --git a/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..9a58346
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments.cmake
new file mode 100644
index 0000000..c4da864
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Output-OUTPUT_VARIABLE-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER OUTPUT_VARIABLE output one_too_many)
diff --git a/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-stderr.txt
new file mode 100644
index 0000000..413ce30
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-PREPEND-NoArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, action PREPEND expects 1 argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments.cmake b/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments.cmake
new file mode 100644
index 0000000..a8e4530
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-PREPEND-NoArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist PREPEND)
diff --git a/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..6ff1b89
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-PREPEND-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments.cmake
new file mode 100644
index 0000000..1f904ad
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-PREPEND-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist PREPEND delta one_too_many)
diff --git a/Tests/RunCMake/list/TRANSFORM-PREPEND.cmake b/Tests/RunCMake/list/TRANSFORM-PREPEND.cmake
new file mode 100644
index 0000000..55b8867
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-PREPEND.cmake
@@ -0,0 +1,48 @@
+set(mylist alpha bravo charlie delta)
+
+list(TRANSFORM mylist PREPEND "P_" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "P_alpha;P_bravo;P_charlie;P_delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${output}\", expected is \"P_alpha;P_bravo;P_charlie;P_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist PREPEND "P_" AT 1 3 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;P_bravo;charlie;P_delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${output}\", expected is \"alpha;P_bravo;charlie;P_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist PREPEND "P_" AT 1 -2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;P_bravo;P_charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${output}\", expected is \"alpha;P_bravo;P_charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist PREPEND "P_" FOR 1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;P_bravo;P_charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${output}\", expected is \"alpha;P_bravo;P_charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist PREPEND "P_" FOR 1 -1 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;P_bravo;P_charlie;P_delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${output}\", expected is \"alpha;P_bravo;P_charlie;P_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist PREPEND "P_" FOR 0 -1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "P_alpha;bravo;P_charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${output}\", expected is \"P_alpha;bravo;P_charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist PREPEND "P_" REGEX "(r|t)a" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;P_bravo;charlie;P_delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${output}\", expected is \"alpha;P_bravo;charlie;P_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist PREPEND "P_" REGEX "(r|t)a")
+if (NOT mylist STREQUAL "alpha;P_bravo;charlie;P_delta")
+  message (FATAL_ERROR "TRANSFORM(PREPEND) is \"${mylist}\", expected is \"alpha;P_bravo;charlie;P_delta\"")
+endif()
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-result.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-stderr.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-stderr.txt
new file mode 100644
index 0000000..334c96e
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TRANSFORM-REPLACE-InvalidRegex.cmake:2 \(list\):
+  list sub-command TRANSFORM, action REPLACE: Failed to compile regex
+  "\^\(alpha\$".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex.cmake b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex.cmake
new file mode 100644
index 0000000..f440c35
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidRegex.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist REPLACE "^(alpha$" "zulu")
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace-result.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-result.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-stderr.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-stderr.txt
new file mode 100644
index 0000000..7671c83
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TRANSFORM-REPLACE-InvalidReplace1.cmake:2 \(list\):
+  list sub-command TRANSFORM, action REPLACE: replace-expression ends in a
+  backslash.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1.cmake b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1.cmake
new file mode 100644
index 0000000..35387f0
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace1.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist REPLACE "^alpha$" "zulu\\")
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-result.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-stderr.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-stderr.txt
new file mode 100644
index 0000000..e0aabd7
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TRANSFORM-REPLACE-InvalidReplace2.cmake:2 \(list\):
+  list sub-command TRANSFORM, action REPLACE: Unknown escape "\\z" in
+  replace-expression.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2.cmake b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2.cmake
new file mode 100644
index 0000000..2f1f2c7
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-InvalidReplace2.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist REPLACE "^alpha$" "\\zulu")
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-stderr.txt
new file mode 100644
index 0000000..3d39e72
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-REPLACE-NoArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, action REPLACE expects 2 argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments.cmake b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments.cmake
new file mode 100644
index 0000000..b7b1e9d
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist REPLACE)
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-stderr.txt
new file mode 100644
index 0000000..dc80f33
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-REPLACE-NoEnoughArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, action REPLACE expects 2 argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments.cmake b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments.cmake
new file mode 100644
index 0000000..1d418c0
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-NoEnoughArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist REPLACE "^alpha$")
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..3d4e15a
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-REPLACE-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments.cmake
new file mode 100644
index 0000000..baed0af
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist REPLACE "^alpha$" "zulu" "one_too_many")
diff --git a/Tests/RunCMake/list/TRANSFORM-REPLACE.cmake b/Tests/RunCMake/list/TRANSFORM-REPLACE.cmake
new file mode 100644
index 0000000..256b1b8
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-REPLACE.cmake
@@ -0,0 +1,48 @@
+set(mylist alpha bravo charlie delta)
+
+list(TRANSFORM mylist REPLACE "(.+a)$" "\\1_\\1" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha_alpha;bravo;charlie;delta_delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${output}\", expected is \"alpha_alpha;bravo;charlie;delta_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist REPLACE "(.+a)$" "\\1_\\1" AT 1 3 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo;charlie;delta_delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${output}\", expected is \"alpha;bravo;charlie;delta_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist REPLACE "(.+e)$" "\\1_\\1" AT 1 -2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo;charlie_charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${output}\", expected is \"alpha;bravo;charlie_charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist REPLACE "(.+e)$" "\\1_\\1" FOR 1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo;charlie_charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${output}\", expected is \"alpha;bravo;charlie_charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist REPLACE "(.+a)$" "\\1_\\1" FOR 1 -1 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo;charlie;delta_delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${output}\", expected is \"alpha;bravo;charlie_A;delta_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist REPLACE "(.+a)$" "\\1_\\1" FOR 0 -1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha_alpha;bravo;charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${output}\", expected is \"alpha_alpha;bravo;charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist REPLACE "(.+a)$" "\\1_\\1" REGEX "(r|t)a" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo;charlie;delta_delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${output}\", expected is \"alpha;bravo;charlie;delta_delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist REPLACE "(.+a)$" "\\1_\\1" REGEX "(r|t)a")
+if (NOT mylist STREQUAL "alpha;bravo;charlie;delta_delta")
+  message (FATAL_ERROR "TRANSFORM(REPLACE) is \"${mylist}\", expected is \"alpha;bravo;charlie;delta_delta\"")
+endif()
diff --git a/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..534f940
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-STRIP-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments.cmake
new file mode 100644
index 0000000..c6a8213
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-STRIP-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist STRIP one_too_many)
diff --git a/Tests/RunCMake/list/TRANSFORM-STRIP.cmake b/Tests/RunCMake/list/TRANSFORM-STRIP.cmake
new file mode 100644
index 0000000..366c63a
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-STRIP.cmake
@@ -0,0 +1,49 @@
+set(mylist " alpha" "bravo " " charlie " delta)
+
+list(TRANSFORM mylist STRIP OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo;charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${output}\", expected is \"alpha;bravo;charlie;delta\"")
+endif()
+
+set(mylist " alpha" "bravo " " charlie " "delta ")
+unset(output)
+list(TRANSFORM mylist STRIP AT 1 3 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL " alpha;bravo; charlie ;delta")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${output}\", expected is \" alpha;bravo; charlie ;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist STRIP AT 1 -2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL " alpha;bravo;charlie;delta ")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${output}\", expected is \" alpha;bravo;charlie;delta \"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist STRIP FOR 1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL " alpha;bravo;charlie;delta ")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${output}\", expected is \" alpha;bravo;charlie;delta \"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist STRIP FOR 1 -1 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL " alpha;bravo;charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${output}\", expected is \" alpha;bravo;charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist STRIP FOR 0 -1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo ;charlie;delta ")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${output}\", expected is \"alpha;bravo ;charlie;delta \"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist STRIP REGEX "(r|t)a" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL " alpha;bravo; charlie ;delta")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${output}\", expected is \" alpha;bravo; charlie ;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist STRIP REGEX "(r|t)a")
+if (NOT mylist STREQUAL " alpha;bravo; charlie ;delta")
+  message (FATAL_ERROR "TRANSFORM(STRIP) is \"${mylist}\", expected is \" alpha;bravo; charlie ;delta\"")
+endif()
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-stderr.txt
new file mode 100644
index 0000000..cec520f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-AT-BadArgument.cmake:2 \(list\):
+  list sub-command TRANSFORM, '1x 2': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument.cmake
new file mode 100644
index 0000000..f61b86b
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-BadArgument.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER AT 0 1x 2)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-stderr.txt
new file mode 100644
index 0000000..7e2898b
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-AT-InvalidIndex.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector AT, index: 3 out of range \(-3, 2\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex.cmake
new file mode 100644
index 0000000..d33586c
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-InvalidIndex.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER AT 0 3 2)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-stderr.txt
new file mode 100644
index 0000000..eaf5281
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-AT-NoArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector AT expects at least one numeric value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments.cmake
new file mode 100644
index 0000000..052b79b
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-AT-NoArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER AT)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-stderr.txt
new file mode 100644
index 0000000..a0f701f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TRANSFORM-Selector-FOR-BadArgument.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector FOR expects, at least, two numeric
+  values.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument.cmake
new file mode 100644
index 0000000..55527be
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-BadArgument.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER FOR 0 1x 2)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-stderr.txt
new file mode 100644
index 0000000..c50cc0a
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-FOR-InvalidIndex.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector FOR, index: 6 out of range \(-3, 2\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex.cmake
new file mode 100644
index 0000000..6e2374e
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-InvalidIndex.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER FOR 0 6 2)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-stderr.txt
new file mode 100644
index 0000000..5881b67
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-FOR-NoArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector FOR expects, at least, two arguments.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments.cmake
new file mode 100644
index 0000000..4902cc9
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER FOR)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-stderr.txt
new file mode 100644
index 0000000..b1081d9
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-FOR-NoEnoughArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector FOR expects, at least, two arguments.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments.cmake
new file mode 100644
index 0000000..81417de
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-NoEnoughArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER FOR 1)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..2221cb3
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-FOR-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, '3': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments.cmake
new file mode 100644
index 0000000..80917d6
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-FOR-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER FOR 0 1 2 3)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-stderr.txt
new file mode 100644
index 0000000..31ba939
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TRANSFORM-Selector-REGEX-InvalidRegex.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector REGEX failed to compile regex
+  "\^\(alpha\$".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex.cmake
new file mode 100644
index 0000000..56e202b
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-InvalidRegex.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER REGEX "^(alpha$")
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-stderr.txt
new file mode 100644
index 0000000..2784785
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TRANSFORM-Selector-REGEX-NoArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, selector REGEX expects 'regular expression'
+  argument.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments.cmake
new file mode 100644
index 0000000..f199d0e
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-NoArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER REGEX)
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..db5b1ff
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-Selector-REGEX-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments.cmake
new file mode 100644
index 0000000..4aa1619
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-Selector-REGEX-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER REGEX "^alpha$" "one_too_many")
diff --git a/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..90248ae
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-TOLOWER-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments.cmake
new file mode 100644
index 0000000..1758e19
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOLOWER-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOLOWER one_too_many)
diff --git a/Tests/RunCMake/list/TRANSFORM-TOLOWER.cmake b/Tests/RunCMake/list/TRANSFORM-TOLOWER.cmake
new file mode 100644
index 0000000..a2d7348
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOLOWER.cmake
@@ -0,0 +1,48 @@
+set(mylist ALPHA BRAVO CHARLIE DELTA)
+
+list(TRANSFORM mylist TOLOWER OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;bravo;charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${output}\", expected is \"alpha;bravo;charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOLOWER AT 1 3 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "ALPHA;bravo;CHARLIE;delta")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${output}\", expected is \"ALPHA;bravo;CHARLIE;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOLOWER AT 1 -2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "ALPHA;bravo;charlie;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${output}\", expected is \"ALPHA;bravo;charlie;DELTA\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOLOWER FOR 1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "ALPHA;bravo;charlie;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${output}\", expected is \"ALPHA;bravo;charlie;DELTA\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOLOWER FOR 1 -1 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "ALPHA;bravo;charlie;delta")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${output}\", expected is \"ALPHA;bravo;charlie;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOLOWER FOR 0 -1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;BRAVO;charlie;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${output}\", expected is \"alpha;BRAVO;charlie;DELTA\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOLOWER REGEX "(R|T)A" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "ALPHA;bravo;CHARLIE;delta")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${output}\", expected is \"ALPHA;bravo;CHARLIE;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOLOWER REGEX "(R|T)A")
+if (NOT mylist STREQUAL "ALPHA;bravo;CHARLIE;delta")
+  message (FATAL_ERROR "TRANSFORM(TOLOWER) is \"${mylist}\", expected is \"ALPHA;bravo;CHARLIE;delta\"")
+endif()
diff --git a/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-result.txt b/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-stderr.txt b/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..9da241b
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TRANSFORM-TOUPPER-TooManyArguments.cmake:2 \(list\):
+  list sub-command TRANSFORM, 'one_too_many': unexpected argument\(s\).
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments.cmake b/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments.cmake
new file mode 100644
index 0000000..58d6a8c
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOUPPER-TooManyArguments.cmake
@@ -0,0 +1,2 @@
+set(mylist alpha bravo charlie)
+list(TRANSFORM mylist TOUPPER one_too_many)
diff --git a/Tests/RunCMake/list/TRANSFORM-TOUPPER.cmake b/Tests/RunCMake/list/TRANSFORM-TOUPPER.cmake
new file mode 100644
index 0000000..5b1fcb6
--- /dev/null
+++ b/Tests/RunCMake/list/TRANSFORM-TOUPPER.cmake
@@ -0,0 +1,48 @@
+set(mylist alpha bravo charlie delta)
+
+list(TRANSFORM mylist TOUPPER OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "ALPHA;BRAVO;CHARLIE;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${output}\", expected is \"ALPHA;BRAVO;CHARLIE;DELTA\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOUPPER AT 1 3 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;BRAVO;charlie;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${output}\", expected is \"alpha;BRAVO;charlie;DELTA\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOUPPER AT 1 -2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;BRAVO;CHARLIE;delta")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${output}\", expected is \"alpha;BRAVO;CHARLIE;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOUPPER FOR 1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;BRAVO;CHARLIE;delta")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${output}\", expected is \"alpha;BRAVO;CHARLIE;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOUPPER FOR 1 -1 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;BRAVO;CHARLIE;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${output}\", expected is \"alpha;BRAVO;CHARLIE;DELTA\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOUPPER FOR 0 -1 2 OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "ALPHA;bravo;CHARLIE;delta")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${output}\", expected is \"ALPHA;bravo;CHARLIE;delta\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOUPPER REGEX "(r|t)a" OUTPUT_VARIABLE output)
+if (NOT output STREQUAL "alpha;BRAVO;charlie;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${output}\", expected is \"alpha;BRAVO;charlie;DELTA\"")
+endif()
+
+unset(output)
+list(TRANSFORM mylist TOUPPER REGEX "(r|t)a")
+if (NOT mylist STREQUAL "alpha;BRAVO;charlie;DELTA")
+  message (FATAL_ERROR "TRANSFORM(TOUPPER) is \"${mylist}\", expected is \"alpha;BRAVO;charlie;DELTA\"")
+endif()
-- 
cgit v0.12