testStringAlgorithms.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst 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 <utility>
  8. #include <vector>
  9. #include <cm/string_view>
  10. #include <cmext/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 (char*)");
  95. assert_ok(cmTokenize(";", ";"_s) == VT{ "" },
  96. "cmTokenize sep (string_view)");
  97. assert_ok(cmTokenize("abc", ";") == VT{ "abc" }, "cmTokenize item");
  98. assert_ok(cmTokenize("abc;", ";") == VT{ "abc" }, "cmTokenize item sep");
  99. assert_ok(cmTokenize(";abc", ";") == VT{ "abc" }, "cmTokenize sep item");
  100. assert_ok(cmTokenize("abc;;efg", ";") == VT{ "abc", "efg" },
  101. "cmTokenize item sep sep item");
  102. assert_ok(cmTokenize("a1;a2;a3;a4", ";") == VT{ "a1", "a2", "a3", "a4" },
  103. "cmTokenize multiple items");
  104. }
  105. {
  106. typedef std::vector<cm::string_view> VT;
  107. assert_ok(cmTokenizedView("", ';') == VT{ "" }, "cmTokenizedView empty");
  108. assert_ok(cmTokenizedView(";", ';') == VT{ "" }, "cmTokenizedView sep");
  109. assert_ok(cmTokenizedView("abc", ';') == VT{ "abc" },
  110. "cmTokenizedView item");
  111. assert_ok(cmTokenizedView("abc;", ';') == VT{ "abc" },
  112. "cmTokenizedView item sep");
  113. assert_ok(cmTokenizedView(";abc", ';') == VT{ "abc" },
  114. "cmTokenizedView sep item");
  115. assert_ok(cmTokenizedView("abc;;efg", ';') == VT{ "abc", "efg" },
  116. "cmTokenizedView item sep sep item");
  117. assert_ok(cmTokenizedView("a1;a2;a3;a4", ';') ==
  118. VT{ "a1", "a2", "a3", "a4" },
  119. "cmTokenizedView multiple items");
  120. }
  121. // ----------------------------------------------------------------------
  122. // Test cmStrCat
  123. {
  124. int ni = -1100;
  125. unsigned int nui = 1100u;
  126. long int nli = -12000l;
  127. unsigned long int nuli = 12000ul;
  128. long long int nlli = -130000ll;
  129. unsigned long long int nulli = 130000ull;
  130. std::string val =
  131. cmStrCat("<test>", ni, ',', nui, ',', nli, ',', nuli, ", ", nlli,
  132. std::string(", "), nulli, cm::string_view("</test>"));
  133. std::string expect =
  134. "<test>-1100,1100,-12000,12000, -130000, 130000</test>";
  135. assert_string(val, expect, "cmStrCat strings and integers");
  136. }
  137. {
  138. float const val = 1.5f;
  139. float const div = 0.00001f;
  140. float f = 0.0f;
  141. std::istringstream(cmStrCat("", val)) >> f;
  142. f -= val;
  143. assert_ok((f < div) && (f > -div), "cmStrCat float");
  144. }
  145. {
  146. double const val = 1.5;
  147. double const div = 0.00001;
  148. double d = 0.0;
  149. std::istringstream(cmStrCat("", val)) >> d;
  150. d -= val;
  151. assert_ok((d < div) && (d > -div), "cmStrCat double");
  152. }
  153. {
  154. std::string val;
  155. std::string expect;
  156. val.reserve(50 * cmStrLen("cmStrCat move ") + 1);
  157. auto data = val.data();
  158. auto capacity = val.capacity();
  159. bool moved = true;
  160. for (int i = 0; i < 100; i++) {
  161. if (i % 2 == 0) {
  162. val = cmStrCat(std::move(val), "move ");
  163. expect += "move ";
  164. } else {
  165. val = cmStrCat("cmStrCat ", std::move(val));
  166. expect = "cmStrCat " + std::move(expect);
  167. }
  168. if (val.data() != data || val.capacity() != capacity) {
  169. moved = false;
  170. }
  171. }
  172. assert_ok(moved, "cmStrCat move");
  173. assert_string(val, expect, "cmStrCat move");
  174. }
  175. // ----------------------------------------------------------------------
  176. // Test cmWrap
  177. {
  178. typedef std::vector<std::string> VT;
  179. assert_string(cmWrap("<", VT{}, ">", "; "), //
  180. "", //
  181. "cmWrap empty, string prefix and suffix");
  182. assert_string(cmWrap("<", VT{ "abc" }, ">", "; "), //
  183. "<abc>", //
  184. "cmWrap single, string prefix and suffix");
  185. assert_string(cmWrap("<", VT{ "a1", "a2", "a3" }, ">", "; "), //
  186. "<a1>; <a2>; <a3>", //
  187. "cmWrap multiple, string prefix and suffix");
  188. assert_string(cmWrap('<', VT{}, '>', "; "), //
  189. "", //
  190. "cmWrap empty, char prefix and suffix");
  191. assert_string(cmWrap('<', VT{ "abc" }, '>', "; "), //
  192. "<abc>", //
  193. "cmWrap single, char prefix and suffix");
  194. assert_string(cmWrap('<', VT{ "a1", "a2", "a3" }, '>', "; "), //
  195. "<a1>; <a2>; <a3>", //
  196. "cmWrap multiple, char prefix and suffix");
  197. }
  198. // ----------------------------------------------------------------------
  199. // Test cmHas(Literal)Prefix and cmHas(Literal)Suffix
  200. {
  201. std::string str("abc");
  202. assert_ok(cmHasPrefix(str, 'a'), "cmHasPrefix char");
  203. assert_ok(!cmHasPrefix(str, 'c'), "cmHasPrefix char not");
  204. assert_ok(cmHasPrefix(str, "ab"), "cmHasPrefix string");
  205. assert_ok(!cmHasPrefix(str, "bc"), "cmHasPrefix string not");
  206. assert_ok(cmHasPrefix(str, str), "cmHasPrefix complete string");
  207. assert_ok(cmHasLiteralPrefix(str, "ab"), "cmHasLiteralPrefix string");
  208. assert_ok(!cmHasLiteralPrefix(str, "bc"), "cmHasLiteralPrefix string not");
  209. assert_ok(cmHasSuffix(str, 'c'), "cmHasSuffix char");
  210. assert_ok(!cmHasSuffix(str, 'a'), "cmHasSuffix char not");
  211. assert_ok(cmHasSuffix(str, "bc"), "cmHasSuffix string");
  212. assert_ok(!cmHasSuffix(str, "ab"), "cmHasSuffix string not");
  213. assert_ok(cmHasSuffix(str, str), "cmHasSuffix complete string");
  214. assert_ok(cmHasLiteralSuffix(str, "bc"), "cmHasLiteralSuffix string");
  215. assert_ok(!cmHasLiteralSuffix(str, "ab"), "cmHasLiteralPrefix string not");
  216. }
  217. // ----------------------------------------------------------------------
  218. // Test cmStrToLong
  219. {
  220. long value;
  221. assert_ok(cmStrToLong("1", &value) && value == 1,
  222. "cmStrToLong parses a positive decimal integer.");
  223. assert_ok(cmStrToLong(" 1", &value) && value == 1,
  224. "cmStrToLong parses a decimal integer after whitespace.");
  225. assert_ok(cmStrToLong("-1", &value) && value == -1,
  226. "cmStrToLong parses a negative decimal integer.");
  227. assert_ok(
  228. cmStrToLong(" -1", &value) && value == -1,
  229. "cmStrToLong parses a negative decimal integer after whitespace.");
  230. assert_ok(!cmStrToLong("1x", &value),
  231. "cmStrToLong rejects trailing content.");
  232. }
  233. // ----------------------------------------------------------------------
  234. // Test cmStrToULong
  235. {
  236. unsigned long value;
  237. assert_ok(cmStrToULong("1", &value) && value == 1,
  238. "cmStrToULong parses a decimal integer.");
  239. assert_ok(cmStrToULong(" 1", &value) && value == 1,
  240. "cmStrToULong parses a decimal integer after whitespace.");
  241. assert_ok(!cmStrToULong("-1", &value),
  242. "cmStrToULong rejects a negative number.");
  243. assert_ok(!cmStrToULong(" -1", &value),
  244. "cmStrToULong rejects a negative number after whitespace.");
  245. assert_ok(!cmStrToULong("1x", &value),
  246. "cmStrToULong rejects trailing content.");
  247. }
  248. // ----------------------------------------------------------------------
  249. // Test cmStrToLongLong
  250. {
  251. long long value;
  252. assert_ok(cmStrToLongLong("1", &value) && value == 1,
  253. "cmStrToLongLong parses a positive decimal integer.");
  254. assert_ok(cmStrToLongLong(" 1", &value) && value == 1,
  255. "cmStrToLongLong parses a decimal integer after whitespace.");
  256. assert_ok(cmStrToLongLong("-1", &value) && value == -1,
  257. "cmStrToLongLong parses a negative decimal integer.");
  258. assert_ok(
  259. cmStrToLongLong(" -1", &value) && value == -1,
  260. "cmStrToLongLong parses a negative decimal integer after whitespace.");
  261. assert_ok(!cmStrToLongLong("1x", &value),
  262. "cmStrToLongLong rejects trailing content.");
  263. }
  264. // ----------------------------------------------------------------------
  265. // Test cmStrToULongLong
  266. {
  267. unsigned long long value;
  268. assert_ok(cmStrToULongLong("1", &value) && value == 1,
  269. "cmStrToULongLong parses a decimal integer.");
  270. assert_ok(cmStrToULongLong(" 1", &value) && value == 1,
  271. "cmStrToULongLong parses a decimal integer after whitespace.");
  272. assert_ok(!cmStrToULongLong("-1", &value),
  273. "cmStrToULongLong rejects a negative number.");
  274. assert_ok(!cmStrToULongLong(" -1", &value),
  275. "cmStrToULongLong rejects a negative number after whitespace.");
  276. assert_ok(!cmStrToULongLong("1x", &value),
  277. "cmStrToULongLong rejects trailing content.");
  278. }
  279. // ----------------------------------------------------------------------
  280. // Test cmStrLen
  281. {
  282. constexpr auto len = cmStrLen("Hello world!");
  283. assert_ok(len == 12,
  284. "cmStrLen returns length of non-empty literal string");
  285. assert_ok(cmStrLen("") == 0,
  286. "cmStrLen returns length of empty literal string");
  287. }
  288. return failed;
  289. }