diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 95ff025dda..ae7ad72d34 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -321,6 +321,21 @@ Version Comparisons String Expressions ------------------ +Most of the expressions in this section are closely associated with the +:command:`string` command, providing the same capabilities, but in +the form of a generator expression. + +In each of the following string-related generator expressions, the ``string`` +must not contain any commas if that generator expression expects something to +be provided after the ``string``. For example, the expression +``$`` requires a ``value`` after the ``string``. +Since a comma is used to separate the ``string`` and the ``value``, the +``string`` cannot itself contain a comma. This restriction does not apply to +the :command:`string` command, it is specific to the string-handling generator +expressions only. The :genex:`$` generator expression can be used to +specify a comma as part of the arguments of the string-related generator +expressions. + .. _`String Comparisons Generator Expressions`: String Comparisons @@ -333,7 +348,7 @@ evaluates to ``1`` if ``${foo}`` is any of ``BAR``, ``Bar``, ``bar``, etc. .. code-block:: cmake - $,BAR> + $,BAR> .. genex:: $ @@ -366,10 +381,337 @@ evaluates to ``1`` if ``${foo}`` is any of ``BAR``, ``Bar``, ``bar``, etc. ``1`` if ``string1`` is lexicographically greater than or equal to ``string2``, else ``0``. +.. _`String Queries Generator Expressions`: + +String Queries +^^^^^^^^^^^^^^ + +.. genex:: $ + + .. versionadded:: 4.3 + + The given string's length in bytes. Note that this means, if ``string`` + contains multi-byte characters, the result will *not* be the number of + characters. + +.. genex:: $ + + .. versionadded:: 4.3 + + The substring of the given ``string``. If ``length`` is ``-1`` or greater + than the ``string`` length the remainder of the string starting at ``begin`` + will be returned. + + Both ``begin`` and ``length`` are counted in bytes, so care must + be exercised if ``string`` could contain multi-byte characters. + +.. genex:: $ + + The position where the given ``substring`` was found in the supplied + ``string``. If the ``substring`` is not found, a position of -1 is returned. + + The ``FROM:`` option defines how the search will be done: + + ``BEGIN`` + The search will start at the beginning of the ``string``. This the default. + + ``END`` + The search will start from the end of the ``string``. + + The ``$`` generator expression treats all strings as ASCII-only + characters. The index returned will also be counted in bytes, so strings + containing multi-byte characters may lead to unexpected results. + +.. genex:: $ + + .. versionadded:: 4.3 + + Match, in the ``string``, the ``regular_expression``. + + The ``SEEK:`` option specifies the match behavior: + + ``ONCE`` + Match only the first occurrence. This is the default. + + ``ALL`` + Match as many times as possible and return the matches as a list. + + See the :ref:`Regular expressions specification ` for + the syntax of the ``regular_expression`` parameter. + +.. _`String Generating Generator Expressions`: + +String Generations +^^^^^^^^^^^^^^^^^^ + +.. genex:: $ + + .. versionadded:: 4.3 + + Join all the ``input`` arguments together using the ``glue`` string. + +.. genex:: $ + + .. versionadded:: 4.3 + + Convert all numbers, in the range 1-255, into corresponding ASCII + characters. Any number outside this range will raise an error. + +.. genex:: $ + + .. versionadded:: 4.3 + + Produce a string representation of the current date and/or time. + + If the generator expression is unable to obtain a timestamp, the result will + be the empty string ``""``. + + The optional ``UTC`` flag requests the current date/time representation to + be in Coordinated Universal Time (UTC) rather than local time. + + If the ``SOURCE_DATE_EPOCH`` environment variable is set, its value will be + used instead of the current time. + See https://reproducible-builds.org/specs/source-date-epoch/ for details. + + The optional ```` may contain the following format specifiers: + + ``%%`` + A literal percent sign (%). + + ``%d`` + The day of the current month (01-31). + + ``%H`` + The hour on a 24-hour clock (00-23). + + ``%I`` + The hour on a 12-hour clock (01-12). + + ``%j`` + The day of the current year (001-366). + + ``%m`` + The month of the current year (01-12). + + ``%b`` + Abbreviated month name (e.g. Oct). + + ``%B`` + Full month name (e.g. October). + + ``%M`` + The minute of the current hour (00-59). + + ``%s`` + Seconds since midnight (UTC) 1-Jan-1970 (UNIX time). + + ``%S`` + The second of the current minute. 60 represents a leap second. (00-60) + + ``%f`` + The microsecond of the current second (000000-999999). + + ``%U`` + The week number of the current year (00-53). + + ``%V`` + The ISO 8601 week number of the current year (01-53). + + ``%w`` + The day of the current week. 0 is Sunday. (0-6) + + ``%a`` + Abbreviated weekday name (e.g. Fri). + + ``%A`` + Full weekday name (e.g. Friday). + + ``%y`` + The last two digits of the current year (00-99). + + ``%Y`` + The current year. + + ``%z`` + The offset of the time zone from UTC, in hours and minutes, + with format ``+hhmm`` or ``-hhmm``. + + ``%Z`` + The time zone name. + + Unknown format specifiers will be ignored and copied to the output + as-is. + + If no explicit ``format`` is given, it will default to: + + * ``%Y-%m-%dT%H:%M:%S`` for local time. + * ``%Y-%m-%dT%H:%M:%SZ`` for UTC. + +.. genex:: $ + + .. versionadded:: 4.3 + + Produce a random string of ASCII characters. The possible options are: + + ``LENGTH:length`` + Define the length of the string. The default length is 5 characters. + + ``ALPHABET:alphabet`` + Define the characters used for the generation. The alphabet is always + interpreted as holding ASCII characters. The default alphabet is all + numbers and upper and lower case letters. + + ``RANDOM_SEED:seed`` + Specify an integer which will be used to seed the random number generator. + +.. genex:: $ + + .. versionadded:: 4.3 + + Create a universally unique identifier (aka GUID) as per RFC4122. + A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`` + where each ``x`` represents an hexadecimal character. + + The UUID is based on the hash of the combined values of: + + ``NAMESPACE:namespace`` + ``namespace`` which has to be a valid UUID. + + ``NAME:name`` + ``name`` is an arbitrary string. + + ``TYPE:`` + The hash algorithm can be either: + + ``MD5`` + Version 3 UUID. + + ``SHA1`` + Version 5 UUID. + + ``CASE:`` + Specify the case of the hexadecimal characters. + + ``LOWER`` + Hexadecimal characters are all of lowercase. This is the default. + + ``UPPER`` + Hexadecimal characters are all of uppercase. + +.. _`String Transforming Generator Expressions`: String Transformations ^^^^^^^^^^^^^^^^^^^^^^ +.. genex:: $ + + .. versionadded:: 4.3 + + Replace all occurrences of ``match_string`` in the ``string`` with + ``replace_string``. + + The ``match_string`` can be of two different types: + + ``STRING`` + ``match_string`` is a literal string and match will be done by simple + string comparison. This is the default. + + ``REGEX`` + ``match_string`` is a regular expression. Match this regular_expression as + many times as possible and substitute the ``replace_string`` for the match + in the ``string``. + + The ``replace_string`` may refer to parenthesis-delimited subexpressions of + the match using \\1, \\2, ..., \\9. Note that two backslashes (\\\\1) are + required in CMake code to get a backslash through argument parsing. + +.. genex:: $ + + .. versionadded:: 4.3 + + Append all the ``input`` arguments to the ``string``. + +.. genex:: $ + + .. versionadded:: 4.3 + + Prepend all the ``input`` arguments to the ``string``. + +.. genex:: $ + + .. versionadded:: 4.3 + + Content of ``string`` converted to lower case. + +.. genex:: $ + + .. versionadded:: 4.3 + + Content of ``string`` converted to upper case. + +.. genex:: $ + + .. versionadded:: 4.3 + + Remove the specified elements from the ``string``. The possible options are: + + ``SPACES`` + Remove the leading and trailing spaces of the ``string``. + +.. genex:: $ + + .. versionadded:: 4.3 + + Escape the specified elements of the ``string``. The possible options are: + + ``REGEX`` + Escape all characters that have special meaning in a regular expressions, + such that the ``string`` can be used as part of a regular expression to + match the input literally. + +.. genex:: $ + + .. versionadded:: 4.3 + + Convert each byte in the ``string`` to its hexadecimal representation. + Letters in the result (a through f) are in lowercase. + +.. genex:: $ + + .. versionadded:: 4.3 + + Compute a cryptographic hash of the ``string``. The supported algorithm + names, as specified by the ``ALGORITHM:`` option are: + + ``MD5`` + Message-Digest Algorithm 5, RFC 1321. + ``SHA1`` + US Secure Hash Algorithm 1, RFC 3174. + ``SHA224`` + US Secure Hash Algorithms, RFC 4634. + ``SHA256`` + US Secure Hash Algorithms, RFC 4634. + ``SHA384`` + US Secure Hash Algorithms, RFC 4634. + ``SHA512`` + US Secure Hash Algorithms, RFC 4634. + ``SHA3_224`` + Keccak SHA-3. + ``SHA3_256`` + Keccak SHA-3. + ``SHA3_384`` + Keccak SHA-3. + ``SHA3_512`` + Keccak SHA-3. + +.. genex:: $ + + .. versionadded:: 4.3 + + Convert each non-alphanumeric character in the ``string`` to an underscore. + If the first character of the ``string`` is a digit, an underscore will also + be prepended. + .. genex:: $ Content of ``string`` converted to lower case. @@ -380,8 +722,8 @@ String Transformations .. genex:: $ - Content of ``...`` converted to a C identifier. The conversion follows the - same behavior as :command:`string(MAKE_C_IDENTIFIER)`. + Content of ``string`` converted to a C identifier. The conversion follows + the same behavior as :command:`string(MAKE_C_IDENTIFIER)`. List Expressions ---------------- diff --git a/Help/release/dev/GenEx-STRING.rst b/Help/release/dev/GenEx-STRING.rst new file mode 100644 index 0000000000..5df81bf2e9 --- /dev/null +++ b/Help/release/dev/GenEx-STRING.rst @@ -0,0 +1,8 @@ +GenEx-STRING +------------ + +* :genex:`$` generator expressions were added for + :ref:`query `, + :ref:`generation `, and + :ref:`transformation ` operations + on strings. diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index e71935be81..599719561d 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -782,6 +783,55 @@ bool CheckGenExParameters(cm::GenEx::Evaluation* eval, return true; }; +template +bool GetNumericArgument(std::string const& arg, IndexType& value) +{ + try { + std::size_t pos; + + if (sizeof(IndexType) == sizeof(long)) { + value = std::stol(arg, &pos); + } else { + value = std::stoll(arg, &pos); + } + + if (pos != arg.length()) { + // this is not a number + return false; + } + } catch (std::invalid_argument const&) { + return false; + } + + return true; +} + +template +bool GetNumericArguments( + cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt, + Arguments args, std::vector& indexes, + cmList::ExpandElements expandElements = cmList::ExpandElements::No) +{ + using IndexRange = cmRange; + IndexRange arguments(args.begin(), args.end()); + cmList list; + if (expandElements == cmList::ExpandElements::Yes) { + list = cmList{ args.begin(), args.end(), expandElements }; + arguments = IndexRange{ list.begin(), list.end() }; + } + + for (auto const& value : arguments) { + IndexType index; + if (!GetNumericArgument(value, index)) { + reportError(eval, cnt->GetOriginalExpression(), + cmStrCat("index: \"", value, "\" is not a valid index")); + return false; + } + indexes.push_back(index); + } + return true; +} + bool CheckPathParametersEx(cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt, cm::string_view option, std::size_t count, @@ -1238,6 +1288,553 @@ static const struct PathEqualNode : public cmGeneratorExpressionNode } } pathEqualNode; +namespace { +inline bool CheckStringParametersEx(cm::GenEx::Evaluation* eval, + GeneratorExpressionContent const* cnt, + cm::string_view option, std::size_t count, + int required = 1, bool exactly = true) +{ + return CheckGenExParameters(eval, cnt, "STRING"_s, option, count, required, + exactly); +} +inline bool CheckStringParameters(cm::GenEx::Evaluation* eval, + GeneratorExpressionContent const* cnt, + cm::string_view option, Arguments args, + int required = 1) +{ + return CheckStringParametersEx(eval, cnt, option, args.size(), required); +}; +} + +static const struct StringNode : public cmGeneratorExpressionNode +{ + StringNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return OneOrMoreParameters; } + + bool AcceptsArbitraryContentParameter() const override { return true; } + + std::string Evaluate( + std::vector const& parameters, cm::GenEx::Evaluation* eval, + GeneratorExpressionContent const* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + static std::unordered_map< + cm::string_view, + std::function> + stringCommands{ + { "LENGTH"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "LENGTH"_s, args)) { + return std::to_string(cm::CMakeString{ args.front() }.Length()); + } + return std::string{}; + } }, + { "SUBSTRING"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "SUBSTRING"_s, args, 3)) { + cm::CMakeString str{ args.front() }; + std::vector indexes; + if (GetNumericArguments(ev, cnt, args.advance(1), indexes)) { + try { + return str.Substring(indexes.front(), indexes.back()); + } catch (std::out_of_range const& e) { + reportError(ev, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + } + return std::string{}; + } }, + { "FIND"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "FIND"_s, args.size(), 2, + false)) { + if (args.size() > 3) { + reportError(ev, cnt->GetOriginalExpression(), + "$ expression expects at " + "most three parameters."); + return std::string{}; + } + + auto const FROM = "FROM:"_s; + + cm::CMakeString str{ args.front() }; + cm::CMakeString::FindFrom from = + cm::CMakeString::FindFrom::Begin; + cm::string_view substring; + + args.advance(1); + if (args.size() == 2) { + cm::CMakeString::FindFrom opt = + static_cast(-1); + + for (auto const& arg : args) { + if (cmHasPrefix(arg, FROM)) { + if (arg != "FROM:BEGIN"_s && arg != "FROM:END"_s) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Invalid value for '", FROM, + "' option. 'BEGIN' or 'END' expected.")); + return std::string{}; + } + opt = arg == "FROM:BEGIN"_s + ? cm::CMakeString::FindFrom::Begin + : cm::CMakeString::FindFrom::End; + } else { + substring = arg; + } + } + if (opt == static_cast(-1)) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Expected option '", FROM, "' is missing.")); + return std::string{}; + } + from = opt; + } else { + substring = args.front(); + } + auto pos = str.Find(substring, from); + return pos == cm::CMakeString::npos ? "-1" : std::to_string(pos); + } + return std::string{}; + } }, + { "MATCH"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "MATCH"_s, args.size(), 2, + false)) { + if (args.size() > 3) { + reportError(ev, cnt->GetOriginalExpression(), + "$ expression expects at " + "most three parameters."); + return std::string{}; + } + + auto const SEEK = "SEEK:"_s; + + cm::CMakeString str{ args.front() }; + cm::CMakeString::MatchItems seek = + cm::CMakeString::MatchItems::Once; + auto const* regex = &args[1]; + + args.advance(1); + if (args.size() == 2) { + cm::CMakeString::MatchItems opt = + static_cast(-1); + + for (auto const& arg : args) { + if (cmHasPrefix(arg, SEEK)) { + if (arg != "SEEK:ONCE"_s && arg != "SEEK:ALL"_s) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Invalid value for '", SEEK, + "' option. 'ONCE' or 'ALL' expected.")); + return std::string{}; + } + opt = arg == "SEEK:ONCE"_s + ? cm::CMakeString::MatchItems::Once + : cm::CMakeString::MatchItems::All; + } else { + regex = &arg; + } + } + if (opt == static_cast(-1)) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Expected option '", SEEK, "' is missing.")); + return std::string{}; + } + seek = opt; + } + + try { + return str.Match(*regex, seek).to_string(); + } catch (std::invalid_argument const& e) { + reportError(ev, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + return std::string{}; + } }, + { "JOIN"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "JOIN"_s, args.size(), 2, + false)) { + auto const& glue = args.front(); + return cm::CMakeString{ args.advance(1), glue }; + } + return std::string{}; + } }, + { "ASCII"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "ASCII"_s, args.size(), 1, + false)) { + try { + return cm::CMakeString{}.FromASCII(args); + } catch (std::invalid_argument const& e) { + reportError(ev, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + return std::string{}; + } }, + { "TIMESTAMP"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + cm::string_view format; + cm::CMakeString::UTC utc = cm::CMakeString::UTC::No; + + if (args.size() == 2 && args.front() != "UTC"_s && + args.back() != "UTC"_s) { + reportError(ev, cnt->GetOriginalExpression(), + "'UTC' option is expected."); + return std::string{}; + } + if (args.size() > 2) { + reportError(ev, cnt->GetOriginalExpression(), + "$ expression expects at most two " + "parameters."); + return std::string{}; + } + + for (auto const& arg : args) { + if (arg == "UTC"_s) { + utc = cm::CMakeString::UTC::Yes; + } else { + format = arg; + } + } + return cm::CMakeString{}.Timestamp(format, utc); + } }, + { "RANDOM"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + auto const ALPHABET = "ALPHABET:"_s; + auto const LENGTH = "LENGTH:"_s; + auto const RANDOM_SEED = "RANDOM_SEED:"_s; + + if (args.size() > 3) { + reportError(ev, cnt->GetOriginalExpression(), + "$ expression expects at most three " + "parameters."); + return std::string{}; + } + + cm::string_view alphabet; + std::size_t length = 5; + bool seed_specified = false; + unsigned int seed = 0; + for (auto const& arg : args) { + if (cmHasPrefix(arg, ALPHABET)) { + alphabet = cm::string_view{ arg.c_str() + ALPHABET.length() }; + continue; + } + if (cmHasPrefix(arg, LENGTH)) { + try { + length = std::stoul(arg.substr(LENGTH.size())); + } catch (std::exception const&) { + reportError(ev, cnt->GetOriginalExpression(), + cmStrCat(arg, ": invalid numeric value for '", + LENGTH, "' option.")); + return std::string{}; + } + continue; + } + if (cmHasPrefix(arg, RANDOM_SEED)) { + try { + seed_specified = true; + seed = static_cast( + std::stoul(arg.substr(RANDOM_SEED.size()))); + } catch (std::exception const&) { + reportError(ev, cnt->GetOriginalExpression(), + cmStrCat(arg, ": invalid numeric value for '", + RANDOM_SEED, "' option.")); + return std::string{}; + } + continue; + } + reportError(ev, cnt->GetOriginalExpression(), + cmStrCat(arg, ": invalid parameter.")); + return std::string{}; + } + + try { + if (seed_specified) { + return cm::CMakeString{}.Random(seed, length, alphabet); + } + return cm::CMakeString{}.Random(length, alphabet); + } catch (std::exception const& e) { + reportError(ev, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } }, + { "UUID"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "UUID"_s, args.size(), 2, + false)) { + auto const NAMESPACE = "NAMESPACE:"_s; + auto const NAME = "NAME:"_s; + auto const TYPE = "TYPE:"_s; + auto const CASE = "CASE:"_s; + + if (args.size() > 4) { + reportError(ev, cnt->GetOriginalExpression(), + "$ expression expects at most four " + "parameters."); + return std::string{}; + } + + cm::string_view nameSpace; + cm::string_view name; + cm::CMakeString::UUIDType type = + static_cast(-1); + cm::CMakeString::Case uuidCase = cm::CMakeString::Case::Lower; + for (auto const& arg : args) { + if (cmHasPrefix(arg, NAMESPACE)) { + nameSpace = + cm::string_view{ arg.c_str() + NAMESPACE.length() }; + if (nameSpace.empty()) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Invalid value for '", NAMESPACE, "' option.")); + return std::string{}; + } + continue; + } + if (cmHasPrefix(arg, NAME)) { + name = cm::string_view{ arg.c_str() + NAME.length() }; + continue; + } + if (cmHasPrefix(arg, TYPE)) { + auto value = cm::string_view{ arg.c_str() + TYPE.length() }; + if (value != "MD5"_s && value != "SHA1"_s) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Invalid value for '", TYPE, + "' option. 'MD5' or 'SHA1' expected.")); + return std::string{}; + } + type = value == "MD5"_s ? cm::CMakeString::UUIDType::MD5 + : cm::CMakeString::UUIDType::SHA1; + continue; + } + if (cmHasPrefix(arg, CASE)) { + auto value = cm::string_view{ arg.c_str() + CASE.length() }; + if (value != "UPPER"_s && value != "LOWER"_s) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Invalid value for '", CASE, + "' option. 'UPPER' or 'LOWER' expected.")); + return std::string{}; + } + uuidCase = value == "UPPER"_s ? cm::CMakeString::Case::Upper + : cm::CMakeString::Case::Lower; + continue; + } + reportError(ev, cnt->GetOriginalExpression(), + cmStrCat(arg, ": invalid parameter.")); + return std::string{}; + } + if (nameSpace.empty()) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Required option '", NAMESPACE, "' is missing.")); + return std::string{}; + } + if (type == static_cast(-1)) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Required option '", TYPE, "' is missing.")); + return std::string{}; + } + + try { + return cm::CMakeString{}.UUID(nameSpace, name, type, uuidCase); + } catch (std::exception const& e) { + reportError(ev, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + return std::string{}; + } }, + { "REPLACE"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "REPLACE"_s, args.size(), 3, + false)) { + if (args.size() > 4) { + reportError(ev, cnt->GetOriginalExpression(), + "$ expression expects at " + "most four parameters."); + return std::string{}; + } + + cm::CMakeString::Regex isRegex = cm::CMakeString::Regex::No; + if (args.size() == 4) { + cm::string_view type = args.front(); + if (type != "STRING"_s && type != "REGEX"_s) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat( + '\'', type, + "' is unexpected. 'STRING' or 'REGEX' expected.")); + return std::string{}; + } + isRegex = type == "STRING"_s ? cm::CMakeString::Regex::No + : cm::CMakeString::Regex::Yes; + args.advance(1); + } + + try { + return cm::CMakeString{ args.front() }.Replace( + args[1], args[2], isRegex); + } catch (std::invalid_argument const& e) { + reportError(ev, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + return std::string{}; + } }, + { "APPEND"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "APPEND"_s, args.size(), 2, + false)) { + cm::CMakeString data{ args.front() }; + return data.Append(args.advance(1)); + } + return std::string{}; + } }, + { "PREPEND"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParametersEx(ev, cnt, "PREPEND "_s, args.size(), 2, + false)) { + cm::CMakeString data{ args.front() }; + return data.Prepend(args.advance(1)); + } + return std::string{}; + } }, + { "TOLOWER"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "TOLOWER"_s, args, 1)) { + return cm::CMakeString{}.ToLower(args.front()); + } + return std::string{}; + } }, + { "TOUPPER"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "TOUPPER"_s, args, 1)) { + return cm::CMakeString{}.ToUpper(args.front()); + } + return std::string{}; + } }, + { "STRIP"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "STRIP"_s, args, 2)) { + if (args.front() != "SPACES"_s) { + reportError(ev, cnt->GetOriginalExpression(), + cmStrCat('\'', args.front(), + "' is unexpected. 'SPACES' expected.")); + return std::string{}; + } + + return cm::CMakeString{ args[1] }.Strip(); + } + return std::string{}; + } }, + { "QUOTE"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "QUOTE"_s, args, 2)) { + if (args.front() != "REGEX"_s) { + reportError(ev, cnt->GetOriginalExpression(), + cmStrCat('\'', args.front(), + "' is unexpected. 'REGEX' expected.")); + return std::string{}; + } + + return cm::CMakeString{ args[1] }.Quote(); + } + return std::string{}; + } }, + { "HEX"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "HEX"_s, args, 1)) { + return cm::CMakeString{ args.front() }.ToHexadecimal(); + } + return std::string{}; + } }, + { "HASH"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "HASH"_s, args, 2)) { + auto const ALGORITHM = "ALGORITHM:"_s; + + if (cmHasPrefix(args[1], ALGORITHM)) { + try { + auto const algo = + cm::string_view{ args[1].c_str() + ALGORITHM.length() }; + if (algo.empty()) { + reportError( + ev, cnt->GetOriginalExpression(), + cmStrCat("Missing value for '", ALGORITHM, "' option.")); + return std::string{}; + } + return cm::CMakeString{ args.front() }.Hash(algo); + } catch (std::exception const& e) { + reportError(ev, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + reportError(ev, cnt->GetOriginalExpression(), + cmStrCat(args[1], ": invalid parameter. Option '", + ALGORITHM, "' expected.")); + } + return std::string{}; + } }, + { "MAKE_C_IDENTIFIER"_s, + [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt, + Arguments& args) -> std::string { + if (CheckStringParameters(ev, cnt, "MAKE_C_IDENTIFIER"_s, args, + 1)) { + return cm::CMakeString{ args.front() }.MakeCIdentifier(); + } + return std::string{}; + } } + }; + + if (parameters.front().empty()) { + reportError(eval, content->GetOriginalExpression(), + "$ expression requires at least one parameter."); + return std::string{}; + } + + if (cm::contains(stringCommands, parameters.front())) { + auto args = Arguments{ parameters }.advance(1); + return stringCommands[parameters.front()](eval, content, args); + } + + reportError(eval, content->GetOriginalExpression(), + cmStrCat(parameters.front(), ": invalid option.")); + return std::string{}; + } +} stringNode; + namespace { inline bool CheckListParametersEx(cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt, @@ -1259,53 +1856,6 @@ inline cmList GetList(std::string const& list) { return list.empty() ? cmList{} : cmList{ list, cmList::EmptyElements::Yes }; } - -bool GetNumericArgument(std::string const& arg, cmList::index_type& value) -{ - try { - std::size_t pos; - - if (sizeof(cmList::index_type) == sizeof(long)) { - value = std::stol(arg, &pos); - } else { - value = std::stoll(arg, &pos); - } - - if (pos != arg.length()) { - // this is not a number - return false; - } - } catch (std::invalid_argument const&) { - return false; - } - - return true; -} - -bool GetNumericArguments( - cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt, - Arguments args, std::vector& indexes, - cmList::ExpandElements expandElements = cmList::ExpandElements::No) -{ - using IndexRange = cmRange; - IndexRange arguments(args.begin(), args.end()); - cmList list; - if (expandElements == cmList::ExpandElements::Yes) { - list = cmList{ args.begin(), args.end(), expandElements }; - arguments = IndexRange{ list.begin(), list.end() }; - } - - for (auto const& value : arguments) { - cmList::index_type index; - if (!GetNumericArgument(value, index)) { - reportError(eval, cnt->GetOriginalExpression(), - cmStrCat("index: \"", value, "\" is not a valid index")); - return false; - } - indexes.push_back(index); - } - return true; -} } static const struct ListNode : public cmGeneratorExpressionNode @@ -4952,6 +5502,7 @@ cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode( { "STRLESS_EQUAL", &strLessEqualNode }, { "STRGREATER", &strGreaterNode }, { "STRGREATER_EQUAL", &strGreaterEqualNode }, + { "STRING", &stringNode }, { "EQUAL", &equalNode }, { "IN_LIST", &inListNode }, { "FILTER", &filterNode }, diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index f031c43e17..a454412902 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -523,6 +523,7 @@ add_RunCMake_test(GenEx-TARGET_IMPORT_FILE) add_RunCMake_test(GenEx-GENEX_EVAL) add_RunCMake_test(GenEx-TARGET_PROPERTY) add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS) +add_RunCMake_test(GenEx-STRING) add_RunCMake_test(GenEx-PATH) add_RunCMake_test(GenEx-PATH_EQUAL) add_RunCMake_test(GenEx-LIST) diff --git a/Tests/RunCMake/GenEx-STRING/APPEND.cmake.in b/Tests/RunCMake/GenEx-STRING/APPEND.cmake.in new file mode 100644 index 0000000000..6c1767b7d7 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/APPEND.cmake.in @@ -0,0 +1,22 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set(reference "abcd") +string(APPEND reference "efg" "ABCD") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +unset(reference) +string(APPEND reference "efg" "ABCD") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:APPEND" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments-stderr.txt new file mode 100644 index 0000000000..d14cdeacc1 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments-stderr.txt @@ -0,0 +1,38 @@ +CMake Error at ASCII-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Character with code foo does not exist. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at ASCII-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Character with code 256 does not exist. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at ASCII-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Character with code 256 does not exist. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at ASCII-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Character with code -1 does not exist. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments.cmake new file mode 100644 index 0000000000..d26a341cf9 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/ASCII-WrongArguments.cmake @@ -0,0 +1,7 @@ + +add_custom_target(check ALL COMMAND check + $ + $ + $ + $ +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/ASCII.cmake.in b/Tests/RunCMake/GenEx-STRING/ASCII.cmake.in new file mode 100644 index 0000000000..4075af436c --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/ASCII.cmake.in @@ -0,0 +1,20 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(ASCII 32 reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(ASCII 32 64 reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:ASCII" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/CMakeLists.txt b/Tests/RunCMake/GenEx-STRING/CMakeLists.txt new file mode 100644 index 0000000000..5161b995a9 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.18...3.25) + +project(${RunCMake_TEST} NONE) + +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments-stderr.txt new file mode 100644 index 0000000000..ad767a1409 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments-stderr.txt @@ -0,0 +1,18 @@ +CMake Error at FIND-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Expected option 'FROM:' is missing. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at FIND-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Invalid value for 'FROM:' option. 'BEGIN' or 'END' expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments.cmake new file mode 100644 index 0000000000..fbcdd94fe7 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/FIND-WrongArguments.cmake @@ -0,0 +1,5 @@ + +add_custom_target(check ALL COMMAND check + $ + $ +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/FIND.cmake.in b/Tests/RunCMake/GenEx-STRING/FIND.cmake.in new file mode 100644 index 0000000000..1d11d35ed0 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/FIND.cmake.in @@ -0,0 +1,48 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(FIND "abcdabcd" "cd" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(FIND "abcdabcd" "cd" reference REVERSE) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(FIND "abcdabcd" "xy" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(FIND "abcdabcd" "xy" reference REVERSE) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:FIND" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments-stderr.txt new file mode 100644 index 0000000000..6edb7f7460 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments-stderr.txt @@ -0,0 +1,18 @@ +CMake Error at HASH-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Missing value for 'ALGORITHM:' option. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at HASH-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + FOO: invalid hash algorithm. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments.cmake new file mode 100644 index 0000000000..3b9fa82775 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/HASH-WrongArguments.cmake @@ -0,0 +1,5 @@ + +add_custom_target(check ALL COMMAND check + $ + $ +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/HASH.cmake.in b/Tests/RunCMake/GenEx-STRING/HASH.cmake.in new file mode 100644 index 0000000000..e1fe2c700d --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/HASH.cmake.in @@ -0,0 +1,69 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +# foreach(hash IN ITEMS MD5 SHA1 SHA224 SHA256 SHA384 SHA512 SHA3_224 SHA3_256 SHA3_384 SHA3_512) + +string(MD5 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA1 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA224 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA256 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA384 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA512 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA3_224 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA3_256 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA3_384 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SHA3_512 reference "sample input string") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +check_errors("STRING:HASH" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/HEX.cmake.in b/Tests/RunCMake/GenEx-STRING/HEX.cmake.in new file mode 100644 index 0000000000..3fff995f82 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/HEX.cmake.in @@ -0,0 +1,20 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(HEX "The quick brown fox jumps over the lazy dog." reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(HEX "Ash nazg durbatulûk. Ash nazg gimbatul. Ash nazg thrakatulûk. Agh burzum-ishi krimpatul" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:HEX" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/JOIN.cmake.in b/Tests/RunCMake/GenEx-STRING/JOIN.cmake.in new file mode 100644 index 0000000000..2441a1369c --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/JOIN.cmake.in @@ -0,0 +1,32 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(JOIN "|" reference "ab" "cd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(JOIN "" reference "ab" "cd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(JOIN "|" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(JOIN "" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:JOIN" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/LENGTH.cmake.in b/Tests/RunCMake/GenEx-STRING/LENGTH.cmake.in new file mode 100644 index 0000000000..5f28f0c7f6 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/LENGTH.cmake.in @@ -0,0 +1,21 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(LENGTH "abc" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +string(LENGTH "" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:LENGTH" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments-stderr.txt new file mode 100644 index 0000000000..a7034a7867 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments-stderr.txt @@ -0,0 +1,28 @@ +CMake Error at MATCH-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Failed to compile regex "\(" +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at MATCH-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Expected option 'SEEK:' is missing. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at MATCH-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Invalid value for 'SEEK:' option. 'ONCE' or 'ALL' expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments.cmake new file mode 100644 index 0000000000..f7d80442c5 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/MATCH-WrongArguments.cmake @@ -0,0 +1,8 @@ + +add_custom_target(check ALL COMMAND check + [[ + $ + $ + $ + ]] +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/MATCH.cmake.in b/Tests/RunCMake/GenEx-STRING/MATCH.cmake.in new file mode 100644 index 0000000000..1e7abf7e34 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/MATCH.cmake.in @@ -0,0 +1,40 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(REGEX MATCH "cd" reference "abcdabcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(REGEX MATCH "(b|B)cd" reference "abcdABcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(REGEX MATCHALL "cd" reference "abcdabcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(REGEX MATCHALL "(b|B)cd" reference "abcdABcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:MATCH" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/PREPEND.cmake.in b/Tests/RunCMake/GenEx-STRING/PREPEND.cmake.in new file mode 100644 index 0000000000..93542ece72 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/PREPEND.cmake.in @@ -0,0 +1,22 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set(reference "abcd") +string(PREPEND reference "efg" "ABCD") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +unset(reference) +string(PREPEND reference "efg" "ABCD") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:PREPEND" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments-stderr.txt new file mode 100644 index 0000000000..8270c94ef8 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at QUOTE-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + 'FOO' is unexpected. 'REGEX' expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments.cmake new file mode 100644 index 0000000000..0ddbbf4d1e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/QUOTE-WrongArguments.cmake @@ -0,0 +1,6 @@ + +add_custom_target(check ALL COMMAND check + [[ + $ + ]] +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/QUOTE.cmake.in b/Tests/RunCMake/GenEx-STRING/QUOTE.cmake.in new file mode 100644 index 0000000000..2bcb238793 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/QUOTE.cmake.in @@ -0,0 +1,21 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(REGEX QUOTE reference "abcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(REGEX QUOTE reference "ab|c+12?3[x-z]$(y)\\t\\r\\n.cma*ke^[:alpha:] ") +set(output [[ +$ ]]) +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:QUOTE" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments-stderr.txt new file mode 100644 index 0000000000..3f0b042407 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments-stderr.txt @@ -0,0 +1,18 @@ +CMake Error at RANDOM-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + LENGTH:foo: invalid numeric value for 'LENGTH:' option. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at RANDOM-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + RANDOM_SEED:foo: invalid numeric value for 'RANDOM_SEED:' option. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments.cmake new file mode 100644 index 0000000000..ac089d627a --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/RANDOM-WrongArguments.cmake @@ -0,0 +1,5 @@ + +add_custom_target(check ALL COMMAND check + $ + $ +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/RANDOM.cmake.in b/Tests/RunCMake/GenEx-STRING/RANDOM.cmake.in new file mode 100644 index 0000000000..e90e1d9e05 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/RANDOM.cmake.in @@ -0,0 +1,32 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(RANDOM RANDOM_SEED 123 reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(RANDOM LENGTH 9 RANDOM_SEED 5 reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(RANDOM LENGTH 9 RANDOM_SEED 5 ALPHABET "" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(RANDOM LENGTH 9 RANDOM_SEED 5 ALPHABET "abcdef123456789" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:RANDOM" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments-stderr.txt new file mode 100644 index 0000000000..843a104525 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments-stderr.txt @@ -0,0 +1,18 @@ +CMake Error at REPLACE-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + 'FOO' is unexpected. 'STRING' or 'REGEX' expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at REPLACE-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Failed to compile regex "\(" +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments.cmake new file mode 100644 index 0000000000..80085b1b06 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/REPLACE-WrongArguments.cmake @@ -0,0 +1,7 @@ + +add_custom_target(check ALL COMMAND check + [[ + $ + $ + ]] +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/REPLACE.cmake.in b/Tests/RunCMake/GenEx-STRING/REPLACE.cmake.in new file mode 100644 index 0000000000..559ad7d2a3 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/REPLACE.cmake.in @@ -0,0 +1,44 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(REPLACE "bcd" "BCD" reference "abcdabcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(REPLACE "bcd" "" reference "abcdabcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(REPLACE "xyz" "BCD" reference "abcdabcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(REGEX REPLACE "bcd" "BCD" reference "abcdabcd") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:REPLACE" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-STRING/RunCMakeTest.cmake new file mode 100644 index 0000000000..d3dba10dc2 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/RunCMakeTest.cmake @@ -0,0 +1,80 @@ + +include(RunCMake) + +run_cmake(no-arguments) +run_cmake(bad-option) + +function(check_string_syntax name test) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-${test}-build) + set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}") + run_cmake_with_options(${test} ${ARGN}) +endfunction() + +## Unexpected arguments +### sub-commands with one argument +foreach (subcommand IN ITEMS LENGTH TOLOWER TOUPPER HEX MAKE_C_IDENTIFIER) + check_string_syntax (${subcommand} unexpected-arg "-DSTRING_ARGUMENTS=${subcommand},ARG1,ARG2") +endforeach() + +### sub-commands with two arguments +foreach (subcommand IN ITEMS HASH STRIP QUOTE) + check_string_syntax (${subcommand} unexpected-arg "-DSTRING_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3") +endforeach() + +### sub-commands with three arguments +foreach (subcommand IN ITEMS SUBSTRING) + check_string_syntax (${subcommand} unexpected-arg "-DSTRING_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3,ARG4") +endforeach() +foreach (subcommand IN ITEMS FIND MATCH RANDOM) + check_string_syntax (${subcommand} unexpected-arg2 "-DSTRING_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3,ARG4") +endforeach() + +### sub-commands with four arguments +foreach (subcommand IN ITEMS REPLACE) + check_string_syntax (${subcommand} unexpected-arg2 "-DSTRING_ARGUMENTS=${subcommand},ARG1,ARG2,ARG3,ARG4,ARG5") +endforeach() + +run_cmake(SUBSTRING-WrongArguments) +run_cmake(FIND-WrongArguments) +run_cmake(MATCH-WrongArguments) +run_cmaKE(ASCII-WrongArguments) +run_cmake(TIMESTAMP-WrongArguments) +run_cmake(RANDOM-WrongArguments) +run_cmake(UUID-WrongArguments) +run_cmake(REPLACE-WrongArguments) +run_cmake(STRIP-WrongArguments) +run_cmake(QUOTE-WrongArguments) +run_cmake(HASH-WrongArguments) + + +function(check_string_execution name) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) + if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(CONFIG_OPTION -DCMAKE_CONFIGURATION_TYPES=Debug) + else() + set(CONFIG_OPTION -DCMAKE_BUILD_TYPE=Debug) + endif() + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_VARIANT_DESCRIPTION " - ${name}") + run_cmake_with_options(generate -DSTRING_TEST=${name} ${CONFIG_OPTION}) + run_cmake_command(check "${CMAKE_COMMAND}" "-DRunCMake_SOURCE_DIR=${RunCMake_SOURCE_DIR}" -P "${RunCMake_TEST_BINARY_DIR}/${name}.cmake") +endfunction() + +check_string_execution (LENGTH) +check_string_execution (SUBSTRING) +check_string_execution (FIND) +check_string_execution (MATCH) +check_string_execution (JOIN) +check_string_execution (ASCII) +check_string_execution (TIMESTAMP) +check_string_execution (RANDOM) +check_string_execution (UUID) +check_string_execution (REPLACE) +check_string_execution (APPEND) +check_string_execution (PREPEND) +check_string_execution (TOLOWER) +check_string_execution (TOUPPER) +check_string_execution (STRIP) +check_string_execution (QUOTE) +check_string_execution (HEX) +check_string_execution (HASH) diff --git a/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments-stderr.txt new file mode 100644 index 0000000000..6663aa4bdf --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at STRIP-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + 'FOO' is unexpected. 'SPACES' expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments.cmake new file mode 100644 index 0000000000..357f2b4b01 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/STRIP-WrongArguments.cmake @@ -0,0 +1,6 @@ + +add_custom_target(check ALL COMMAND check + [[ + $ + ]] +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/STRIP.cmake.in b/Tests/RunCMake/GenEx-STRING/STRIP.cmake.in new file mode 100644 index 0000000000..4f51c0291c --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/STRIP.cmake.in @@ -0,0 +1,14 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(STRIP " ABCD " reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:STRIP" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments-stderr.txt new file mode 100644 index 0000000000..7d65b417f0 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments-stderr.txt @@ -0,0 +1,38 @@ +CMake Error at SUBSTRING-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + index: "foo" is not a valid index +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at SUBSTRING-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + index: "foo" is not a valid index +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at SUBSTRING-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + begin index: -1 is out of range 0 - 6 +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at SUBSTRING-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + end index: -2 should be -1 or greater +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments.cmake new file mode 100644 index 0000000000..1c39a375b9 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/SUBSTRING-WrongArguments.cmake @@ -0,0 +1,7 @@ + +add_custom_target(check ALL COMMAND check + $ + $ + $ + $ +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/SUBSTRING.cmake.in b/Tests/RunCMake/GenEx-STRING/SUBSTRING.cmake.in new file mode 100644 index 0000000000..6ff4ad4ca1 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/SUBSTRING.cmake.in @@ -0,0 +1,26 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(SUBSTRING "abcd" 1 2 reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SUBSTRING "abcd" 1 -1 reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(SUBSTRING "abcd" 1 5 reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:SUBSTRING" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments-stderr.txt new file mode 100644 index 0000000000..ebcb19ea3d --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at TIMESTAMP-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + 'UTC' option is expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments.cmake new file mode 100644 index 0000000000..012aaf7655 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/TIMESTAMP-WrongArguments.cmake @@ -0,0 +1,4 @@ + +add_custom_target(check ALL COMMAND check + $ +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/TIMESTAMP.cmake.in b/Tests/RunCMake/GenEx-STRING/TIMESTAMP.cmake.in new file mode 100644 index 0000000000..adc2b98353 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/TIMESTAMP.cmake.in @@ -0,0 +1,27 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set(ENV{SOURCE_DATE_EPOCH} "1123456789") + +string(TIMESTAMP reference "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s TZ=%Z tz=%z") +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +string(TIMESTAMP reference "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s TZ=%Z tz=%z" UTC) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:TIMESTAMP" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/TOLOWER.cmake.in b/Tests/RunCMake/GenEx-STRING/TOLOWER.cmake.in new file mode 100644 index 0000000000..dfb18d60ed --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/TOLOWER.cmake.in @@ -0,0 +1,26 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(TOLOWER "ABCD" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(TOLOWER "abcd" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(TOLOWER "abcdABCD12@!" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:TOLOWER" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/TOUPPER.cmake.in b/Tests/RunCMake/GenEx-STRING/TOUPPER.cmake.in new file mode 100644 index 0000000000..562c4f1ccb --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/TOUPPER.cmake.in @@ -0,0 +1,26 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +string(TOUPPER "abcd" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(TOUPPER "ABCD" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(TOUPPER "abcdABCD12@!" reference) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:TOUPPER" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments-result.txt b/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments-stderr.txt new file mode 100644 index 0000000000..e2e4317aff --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments-stderr.txt @@ -0,0 +1,28 @@ +CMake Error at UUID-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Invalid value for 'NAMESPACE:' option. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at UUID-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Invalid value for 'TYPE:' option. 'MD5' or 'SHA1' expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at UUID-WrongArguments\.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$ + + Invalid value for 'CASE:' option. 'UPPER' or 'LOWER' expected. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments.cmake b/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments.cmake new file mode 100644 index 0000000000..72783b85bd --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/UUID-WrongArguments.cmake @@ -0,0 +1,6 @@ + +add_custom_target(check ALL COMMAND check + $ + $ + $ +VERBATIM) diff --git a/Tests/RunCMake/GenEx-STRING/UUID.cmake.in b/Tests/RunCMake/GenEx-STRING/UUID.cmake.in new file mode 100644 index 0000000000..47b7690016 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/UUID.cmake.in @@ -0,0 +1,32 @@ + +cmake_minimum_required(VERSION 4.2...4.3) + +include ("${RunCMake_SOURCE_DIR}/check_errors.cmake") +unset (errors) + +set(UUID_DNS_NAMESPACE 6ba7b810-9dad-11d1-80b4-00c04fd430c8) + +string(UUID reference NAMESPACE ${UUID_DNS_NAMESPACE} NAME www.example.com TYPE MD5) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(UUID reference NAMESPACE ${UUID_DNS_NAMESPACE} NAME www.example.com TYPE MD5 UPPER) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + +string(UUID reference NAMESPACE ${UUID_DNS_NAMESPACE} NAME www.example.com TYPE SHA1) +set(output "$") +if (NOT output STREQUAL reference) + list (APPEND errors " returns bad data: ${output}") +endif() + + +check_errors("STRING:UUID" ${errors}) diff --git a/Tests/RunCMake/GenEx-STRING/bad-option-result.txt b/Tests/RunCMake/GenEx-STRING/bad-option-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/bad-option-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/bad-option-stderr.txt b/Tests/RunCMake/GenEx-STRING/bad-option-stderr.txt new file mode 100644 index 0000000000..2c861024d8 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/bad-option-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at bad-option\.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$ + + BAD_OPTION: invalid option. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/bad-option.cmake b/Tests/RunCMake/GenEx-STRING/bad-option.cmake new file mode 100644 index 0000000000..c6ca81725e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/bad-option.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT result.txt CONTENT "$") diff --git a/Tests/RunCMake/GenEx-STRING/check_errors.cmake b/Tests/RunCMake/GenEx-STRING/check_errors.cmake new file mode 100644 index 0000000000..462475cac7 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/check_errors.cmake @@ -0,0 +1,13 @@ + +function (CHECK_ERRORS command) + set (errors ${ARGN}) + set (command "$<${command}>") + if (errors) + string (LENGTH "${command}" length) + math (EXPR count "${length} + 2") + string (REPEAT " " ${count} shift) + list (TRANSFORM errors PREPEND "${shift}$") + list (JOIN errors "\n" msg) + message (FATAL_ERROR "${command}: ${msg}") + endif() +endfunction() diff --git a/Tests/RunCMake/GenEx-STRING/generate.cmake b/Tests/RunCMake/GenEx-STRING/generate.cmake new file mode 100644 index 0000000000..8d3d40922f --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/generate.cmake @@ -0,0 +1,6 @@ + +if (STRING_TEST STREQUAL "TIMESTAMP") + set(ENV{SOURCE_DATE_EPOCH} "1123456789") +endif() + +file(GENERATE OUTPUT "${STRING_TEST}.cmake" INPUT "${STRING_TEST}.cmake.in") diff --git a/Tests/RunCMake/GenEx-STRING/no-arguments-result.txt b/Tests/RunCMake/GenEx-STRING/no-arguments-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/no-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/no-arguments-stderr.txt b/Tests/RunCMake/GenEx-STRING/no-arguments-stderr.txt new file mode 100644 index 0000000000..6f789bb496 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/no-arguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at no-arguments\.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$ + + \$ expression requires at least one parameter. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/no-arguments.cmake b/Tests/RunCMake/GenEx-STRING/no-arguments.cmake new file mode 100644 index 0000000000..ee473800ce --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/no-arguments.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT result.txt CONTENT "$") diff --git a/Tests/RunCMake/GenEx-STRING/unexpected-arg-result.txt b/Tests/RunCMake/GenEx-STRING/unexpected-arg-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/unexpected-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/unexpected-arg-stderr.txt b/Tests/RunCMake/GenEx-STRING/unexpected-arg-stderr.txt new file mode 100644 index 0000000000..ef0c038a4b --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/unexpected-arg-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at unexpected-arg\.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$ + + \$ expression requires exactly (one|two|three) parameters?. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/unexpected-arg.cmake b/Tests/RunCMake/GenEx-STRING/unexpected-arg.cmake new file mode 100644 index 0000000000..793fbb1867 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/unexpected-arg.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT result.txt CONTENT "$") diff --git a/Tests/RunCMake/GenEx-STRING/unexpected-arg2-result.txt b/Tests/RunCMake/GenEx-STRING/unexpected-arg2-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/unexpected-arg2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-STRING/unexpected-arg2-stderr.txt b/Tests/RunCMake/GenEx-STRING/unexpected-arg2-stderr.txt new file mode 100644 index 0000000000..27c8b1a1a0 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/unexpected-arg2-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at unexpected-arg2\.cmake:[0-9]+ \(file\): + Error evaluating generator expression: + + \$ + + \$ expression expects at most (two|three|four) parameters?. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-STRING/unexpected-arg2.cmake b/Tests/RunCMake/GenEx-STRING/unexpected-arg2.cmake new file mode 100644 index 0000000000..793fbb1867 --- /dev/null +++ b/Tests/RunCMake/GenEx-STRING/unexpected-arg2.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT result.txt CONTENT "$")