testStringAlgorithms.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include <cmConfigure.h> // IWYU pragma: keep
  4. #include <iostream>
  5. #include <sstream>
  6. #include <string>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <vector>
  10. #include <cm/string_view>
  11. #include "cmStringAlgorithms.h"
  12. int testStringAlgorithms(int /*unused*/, char* /*unused*/ [])
  13. {
  14. int failed = 0;
  15. auto assert_ok = [&failed](bool test, cm::string_view title) {
  16. if (test) {
  17. std::cout << "Passed: " << title << "\n";
  18. } else {
  19. std::cout << "Failed: " << title << "\n";
  20. ++failed;
  21. }
  22. };
  23. auto assert_string = [&failed](cm::string_view generated,
  24. cm::string_view expected,
  25. cm::string_view title) {
  26. if (generated == expected) {
  27. std::cout << "Passed: " << title << "\n";
  28. } else {
  29. std::cout << "Failed: " << title << "\n";
  30. std::cout << "Expected: " << expected << "\n";
  31. std::cout << "Got: " << generated << "\n";
  32. ++failed;
  33. }
  34. };
  35. // ----------------------------------------------------------------------
  36. // Test cmTrimWhitespace
  37. {
  38. std::string base = "base";
  39. std::string spaces = " \f\f\n\n\r\r\t\t\v\v";
  40. assert_string(cmTrimWhitespace(spaces + base), base,
  41. "cmTrimWhitespace front");
  42. assert_string(cmTrimWhitespace(base + spaces), base,
  43. "cmTrimWhitespace back");
  44. assert_string(cmTrimWhitespace(spaces + base + spaces), base,
  45. "cmTrimWhitespace front and back");
  46. }
  47. // ----------------------------------------------------------------------
  48. // Test cmRemoveQuotes
  49. {
  50. auto test = [&assert_string](cm::string_view source,
  51. cm::string_view expected,
  52. cm::string_view title) {
  53. assert_string(cmRemoveQuotes(source), expected, title);
  54. };
  55. test("", "", "cmRemoveQuotes empty");
  56. test("\"", "\"", "cmRemoveQuotes single quote");
  57. test("\"\"", "", "cmRemoveQuotes double quote");
  58. test("\"a", "\"a", "cmRemoveQuotes quote char");
  59. test("\"ab", "\"ab", "cmRemoveQuotes quote char char");
  60. test("a\"", "a\"", "cmRemoveQuotes char quote");
  61. test("ab\"", "ab\"", "cmRemoveQuotes char char quote");
  62. test("a", "a", "cmRemoveQuotes single char");
  63. test("ab", "ab", "cmRemoveQuotes two chars");
  64. test("abc", "abc", "cmRemoveQuotes three chars");
  65. test("\"abc\"", "abc", "cmRemoveQuotes quoted chars");
  66. test("\"\"abc\"\"", "\"abc\"", "cmRemoveQuotes quoted quoted chars");
  67. }
  68. // ----------------------------------------------------------------------
  69. // Test cmEscapeQuotes
  70. {
  71. assert_string(cmEscapeQuotes("plain"), "plain", "cmEscapeQuotes plain");
  72. std::string base = "\"base\"\"";
  73. std::string result = "\\\"base\\\"\\\"";
  74. assert_string(cmEscapeQuotes(base), result, "cmEscapeQuotes escaped");
  75. }
  76. // ----------------------------------------------------------------------
  77. // Test cmJoin
  78. {
  79. typedef std::string ST;
  80. typedef std::vector<std::string> VT;
  81. assert_string(cmJoin(ST("abc"), ";"), "a;b;c", "cmJoin std::string");
  82. assert_string(cmJoin(VT{}, ";"), "", "cmJoin std::vector empty");
  83. assert_string(cmJoin(VT{ "a" }, ";"), "a", "cmJoin std::vector single");
  84. assert_string(cmJoin(VT{ "a", "b", "c" }, ";"), "a;b;c",
  85. "cmJoin std::vector multiple");
  86. assert_string(cmJoin(VT{ "a", "b", "c" }, "<=>"), "a<=>b<=>c",
  87. "cmJoin std::vector long sep");
  88. }
  89. // ----------------------------------------------------------------------
  90. // Test cmTokenize
  91. {
  92. typedef std::vector<std::string> VT;
  93. assert_ok(cmTokenize("", ";") == VT{ "" }, "cmTokenize empty");
  94. assert_ok(cmTokenize(";", ";") == VT{ "" }, "cmTokenize sep");
  95. assert_ok(cmTokenize("abc", ";") == VT{ "abc" }, "cmTokenize item");
  96. assert_ok(cmTokenize("abc;", ";") == VT{ "abc" }, "cmTokenize item sep");
  97. assert_ok(cmTokenize(";abc", ";") == VT{ "abc" }, "cmTokenize sep item");
  98. assert_ok(cmTokenize("abc;;efg", ";") == VT{ "abc", "efg" },
  99. "cmTokenize item sep sep item");
  100. assert_ok(cmTokenize("a1;a2;a3;a4", ";") == VT{ "a1", "a2", "a3", "a4" },
  101. "cmTokenize multiple items");
  102. }
  103. // ----------------------------------------------------------------------
  104. // Test cmStrCat
  105. {
  106. int ni = -1100;
  107. unsigned int nui = 1100u;
  108. long int nli = -12000l;
  109. unsigned long int nuli = 12000ul;
  110. long long int nlli = -130000ll;
  111. unsigned long long int nulli = 130000ull;
  112. std::string val =
  113. cmStrCat("<test>", ni, ',', nui, ',', nli, ",", nuli, ", ", nlli,
  114. std::string(", "), nulli, cm::string_view("</test>"));
  115. std::string expect =
  116. "<test>-1100,1100,-12000,12000, -130000, 130000</test>";
  117. assert_string(val, expect, "cmStrCat strings and integers");
  118. }
  119. {
  120. float const val = 1.5f;
  121. float const div = 0.00001f;
  122. float f = 0.0f;
  123. std::istringstream(cmStrCat("", val)) >> f;
  124. f -= val;
  125. assert_ok((f < div) && (f > -div), "cmStrCat float");
  126. }
  127. {
  128. double const val = 1.5;
  129. double const div = 0.00001;
  130. double d = 0.0;
  131. std::istringstream(cmStrCat("", val)) >> d;
  132. d -= val;
  133. assert_ok((d < div) && (d > -div), "cmStrCat double");
  134. }
  135. {
  136. std::string val;
  137. std::string expect;
  138. val.reserve(120 * cmStrLen("cmStrCat move"));
  139. auto data = val.data();
  140. for (int i = 0; i < 100; i++) {
  141. val = cmStrCat(std::move(val), "cmStrCat move");
  142. expect += "cmStrCat move";
  143. }
  144. assert_ok((val.data() == data), "cmStrCat move");
  145. assert_string(val, expect, "cmStrCat move");
  146. }
  147. // ----------------------------------------------------------------------
  148. // Test cmWrap
  149. {
  150. typedef std::vector<std::string> VT;
  151. assert_string(cmWrap("<", VT{}, ">", "; "), //
  152. "", //
  153. "cmWrap empty, string prefix and suffix");
  154. assert_string(cmWrap("<", VT{ "abc" }, ">", "; "), //
  155. "<abc>", //
  156. "cmWrap single, string prefix and suffix");
  157. assert_string(cmWrap("<", VT{ "a1", "a2", "a3" }, ">", "; "), //
  158. "<a1>; <a2>; <a3>", //
  159. "cmWrap multiple, string prefix and suffix");
  160. assert_string(cmWrap('<', VT{}, '>', "; "), //
  161. "", //
  162. "cmWrap empty, char prefix and suffix");
  163. assert_string(cmWrap('<', VT{ "abc" }, '>', "; "), //
  164. "<abc>", //
  165. "cmWrap single, char prefix and suffix");
  166. assert_string(cmWrap('<', VT{ "a1", "a2", "a3" }, '>', "; "), //
  167. "<a1>; <a2>; <a3>", //
  168. "cmWrap multiple, char prefix and suffix");
  169. }
  170. // ----------------------------------------------------------------------
  171. // Test cmHas(Literal)Prefix and cmHas(Literal)Suffix
  172. {
  173. std::string str("abc");
  174. assert_ok(cmHasPrefix(str, 'a'), "cmHasPrefix char");
  175. assert_ok(!cmHasPrefix(str, 'c'), "cmHasPrefix char not");
  176. assert_ok(cmHasPrefix(str, "ab"), "cmHasPrefix string");
  177. assert_ok(!cmHasPrefix(str, "bc"), "cmHasPrefix string not");
  178. assert_ok(cmHasPrefix(str, str), "cmHasPrefix complete string");
  179. assert_ok(cmHasLiteralPrefix(str, "ab"), "cmHasLiteralPrefix string");
  180. assert_ok(!cmHasLiteralPrefix(str, "bc"), "cmHasLiteralPrefix string not");
  181. assert_ok(cmHasSuffix(str, 'c'), "cmHasSuffix char");
  182. assert_ok(!cmHasSuffix(str, 'a'), "cmHasSuffix char not");
  183. assert_ok(cmHasSuffix(str, "bc"), "cmHasSuffix string");
  184. assert_ok(!cmHasSuffix(str, "ab"), "cmHasSuffix string not");
  185. assert_ok(cmHasSuffix(str, str), "cmHasSuffix complete string");
  186. assert_ok(cmHasLiteralSuffix(str, "bc"), "cmHasLiteralSuffix string");
  187. assert_ok(!cmHasLiteralSuffix(str, "ab"), "cmHasLiteralPrefix string not");
  188. }
  189. // ----------------------------------------------------------------------
  190. // Test cmStrToLong
  191. {
  192. long value;
  193. assert_ok(cmStrToLong("1", &value) && value == 1,
  194. "cmStrToLong parses a positive decimal integer.");
  195. assert_ok(cmStrToLong(" 1", &value) && value == 1,
  196. "cmStrToLong parses a decimal integer after whitespace.");
  197. assert_ok(cmStrToLong("-1", &value) && value == -1,
  198. "cmStrToLong parses a negative decimal integer.");
  199. assert_ok(
  200. cmStrToLong(" -1", &value) && value == -1,
  201. "cmStrToLong parses a negative decimal integer after whitespace.");
  202. assert_ok(!cmStrToLong("1x", &value),
  203. "cmStrToLong rejects trailing content.");
  204. }
  205. // ----------------------------------------------------------------------
  206. // Test cmStrToULong
  207. {
  208. unsigned long value;
  209. assert_ok(cmStrToULong("1", &value) && value == 1,
  210. "cmStrToULong parses a decimal integer.");
  211. assert_ok(cmStrToULong(" 1", &value) && value == 1,
  212. "cmStrToULong parses a decimal integer after whitespace.");
  213. assert_ok(!cmStrToULong("-1", &value),
  214. "cmStrToULong rejects a negative number.");
  215. assert_ok(!cmStrToULong(" -1", &value),
  216. "cmStrToULong rejects a negative number after whitespace.");
  217. assert_ok(!cmStrToULong("1x", &value),
  218. "cmStrToULong rejects trailing content.");
  219. }
  220. // ----------------------------------------------------------------------
  221. // Test cmStrToLongLong
  222. {
  223. long long value;
  224. assert_ok(cmStrToLongLong("1", &value) && value == 1,
  225. "cmStrToLongLong parses a positive decimal integer.");
  226. assert_ok(cmStrToLongLong(" 1", &value) && value == 1,
  227. "cmStrToLongLong parses a decimal integer after whitespace.");
  228. assert_ok(cmStrToLongLong("-1", &value) && value == -1,
  229. "cmStrToLongLong parses a negative decimal integer.");
  230. assert_ok(
  231. cmStrToLongLong(" -1", &value) && value == -1,
  232. "cmStrToLongLong parses a negative decimal integer after whitespace.");
  233. assert_ok(!cmStrToLongLong("1x", &value),
  234. "cmStrToLongLong rejects trailing content.");
  235. }
  236. // ----------------------------------------------------------------------
  237. // Test cmStrToULongLong
  238. {
  239. unsigned long long value;
  240. assert_ok(cmStrToULongLong("1", &value) && value == 1,
  241. "cmStrToULongLong parses a decimal integer.");
  242. assert_ok(cmStrToULongLong(" 1", &value) && value == 1,
  243. "cmStrToULongLong parses a decimal integer after whitespace.");
  244. assert_ok(!cmStrToULongLong("-1", &value),
  245. "cmStrToULongLong rejects a negative number.");
  246. assert_ok(!cmStrToULongLong(" -1", &value),
  247. "cmStrToULongLong rejects a negative number after whitespace.");
  248. assert_ok(!cmStrToULongLong("1x", &value),
  249. "cmStrToULongLong rejects trailing content.");
  250. }
  251. // ----------------------------------------------------------------------
  252. // Test cmStrLen
  253. {
  254. constexpr auto len = cmStrLen("Hello world!");
  255. assert_ok(len == 12,
  256. "cmStrLen returns length of non-empty literal string");
  257. assert_ok(cmStrLen("") == 0,
  258. "cmStrLen returns length of empty literal string");
  259. }
  260. return failed;
  261. }