tstrutils.nim 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. discard """
  2. matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
  3. """
  4. import std/strutils
  5. from stdtest/testutils import disableVm
  6. import std/assertions
  7. import std/private/jsutils
  8. # xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed
  9. template rejectParse(e) =
  10. try:
  11. discard e
  12. raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e))
  13. except ValueError: discard
  14. template main() =
  15. block: # strip
  16. doAssert strip(" ha ") == "ha"
  17. doAssert strip(" foofoofoo ") == "foofoofoo"
  18. doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
  19. doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
  20. doAssert strip("stripme but don't strip this stripme",
  21. chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
  22. " but don't strip this "
  23. doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
  24. doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
  25. block:
  26. let a = "xxxxxx"
  27. doAssert a.strip(chars={'x'}).len == 0
  28. doAssert "".strip(chars={'x'}).len == 0
  29. doAssert " ".strip(chars={'x'}) == " "
  30. doAssert "xxx xxx".strip(chars={'x'}) == " "
  31. doAssert "xxx wind".strip(chars={'x'}) == " wind"
  32. doAssert "xxx iii".strip(chars={'i'}) == "xxx "
  33. doAssert "x".strip(leading = false, chars={'x'}).len == 0
  34. doAssert "x".strip(trailing = false, chars={'x'}).len == 0
  35. doAssert "x".strip(leading = false, trailing = false, chars={'x'}) == "x"
  36. block: # split
  37. var ret: seq[string] # or use `toSeq` or `collect`
  38. for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p
  39. doAssert ret == @["/home/a1", "xyz", "/usr/bin"]
  40. let s = " this is an example "
  41. let s2 = ":this;is;an:example;;"
  42. doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
  43. doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example",
  44. "", ""]
  45. doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "]
  46. doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "]
  47. doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "]
  48. # Empty string:
  49. doAssert "".split() == @[""]
  50. doAssert "".split(" ") == @[""]
  51. doAssert "".split({' '}) == @[""]
  52. # Empty separators:
  53. doAssert "".split({}) == @[""]
  54. doAssert "".split("") == @[""]
  55. doAssert s.split({}) == @[s]
  56. doAssert s.split("") == @[s]
  57. block: # splitLines
  58. let fixture = "a\nb\rc\r\nd"
  59. doAssert len(fixture.splitLines) == 4
  60. doAssert splitLines(fixture) == @["a", "b", "c", "d"]
  61. doAssert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"]
  62. block: # rsplit
  63. doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"]
  64. doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"]
  65. doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[" foo bar", ""]
  66. doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"]
  67. doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"]
  68. doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"]
  69. doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"]
  70. # Empty string:
  71. doAssert "".rsplit() == @[""]
  72. doAssert "".rsplit(" ") == @[""]
  73. doAssert "".rsplit({' '}) == @[""]
  74. # Empty separators:
  75. let s = " this is an example "
  76. doAssert "".rsplit({}) == @[""]
  77. doAssert "".rsplit("") == @[""]
  78. doAssert s.rsplit({}) == @[s]
  79. doAssert s.rsplit("") == @[s]
  80. block: # splitWhitespace
  81. let s = " this is an example "
  82. doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
  83. doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "]
  84. doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "]
  85. doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "]
  86. doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"]
  87. block: # removeSuffix
  88. var s = "hello\n\r"
  89. s.removeSuffix
  90. doAssert s == "hello"
  91. s.removeSuffix
  92. doAssert s == "hello"
  93. s = "hello\n\n"
  94. s.removeSuffix
  95. doAssert s == "hello"
  96. s = "hello\r"
  97. s.removeSuffix
  98. doAssert s == "hello"
  99. s = "hello \n there"
  100. s.removeSuffix
  101. doAssert s == "hello \n there"
  102. s = "hello"
  103. s.removeSuffix("llo")
  104. doAssert s == "he"
  105. s.removeSuffix('e')
  106. doAssert s == "h"
  107. s = "hellos"
  108. s.removeSuffix({'s','z'})
  109. doAssert s == "hello"
  110. s.removeSuffix({'l','o'})
  111. doAssert s == "he"
  112. s = "aeiou"
  113. s.removeSuffix("")
  114. doAssert s == "aeiou"
  115. s = ""
  116. s.removeSuffix("")
  117. doAssert s == ""
  118. s = " "
  119. s.removeSuffix
  120. doAssert s == " "
  121. s = " "
  122. s.removeSuffix("")
  123. doAssert s == " "
  124. s = " "
  125. s.removeSuffix(" ")
  126. doAssert s == " "
  127. s = " "
  128. s.removeSuffix(' ')
  129. doAssert s == ""
  130. # Contrary to Chomp in other languages
  131. # empty string does not change behaviour
  132. s = "hello\r\n\r\n"
  133. s.removeSuffix("")
  134. doAssert s == "hello\r\n\r\n"
  135. block: # removePrefix
  136. var s = "\n\rhello"
  137. s.removePrefix
  138. doAssert s == "hello"
  139. s.removePrefix
  140. doAssert s == "hello"
  141. s = "\n\nhello"
  142. s.removePrefix
  143. doAssert s == "hello"
  144. s = "\rhello"
  145. s.removePrefix
  146. doAssert s == "hello"
  147. s = "hello \n there"
  148. s.removePrefix
  149. doAssert s == "hello \n there"
  150. s = "hello"
  151. s.removePrefix("hel")
  152. doAssert s == "lo"
  153. s.removePrefix('l')
  154. doAssert s == "o"
  155. s = "hellos"
  156. s.removePrefix({'h','e'})
  157. doAssert s == "llos"
  158. s.removePrefix({'l','o'})
  159. doAssert s == "s"
  160. s = "aeiou"
  161. s.removePrefix("")
  162. doAssert s == "aeiou"
  163. s = ""
  164. s.removePrefix("")
  165. doAssert s == ""
  166. s = " "
  167. s.removePrefix
  168. doAssert s == " "
  169. s = " "
  170. s.removePrefix("")
  171. doAssert s == " "
  172. s = " "
  173. s.removePrefix(" ")
  174. doAssert s == " "
  175. s = " "
  176. s.removePrefix(' ')
  177. doAssert s == ""
  178. # Contrary to Chomp in other languages
  179. # empty string does not change behaviour
  180. s = "\r\n\r\nhello"
  181. s.removePrefix("")
  182. doAssert s == "\r\n\r\nhello"
  183. block: # delete(slice)
  184. var s = "0123456789ABCDEFGH"
  185. delete(s, 4 .. 5)
  186. doAssert s == "01236789ABCDEFGH"
  187. delete(s, s.len-1 .. s.len-1)
  188. doAssert s == "01236789ABCDEFG"
  189. delete(s, 0..0)
  190. doAssert s == "1236789ABCDEFG"
  191. s = ""
  192. doAssertRaises(IndexDefect): delete(s, 0..0)
  193. doAssert s == ""
  194. s = "abc"
  195. doAssertRaises(IndexDefect): delete(s, -1 .. -2)
  196. doAssertRaises(IndexDefect): delete(s, 2..3)
  197. doAssertRaises(IndexDefect): delete(s, 3..2)
  198. delete(s, 2..2)
  199. doAssert s == "ab"
  200. delete(s, 1..0)
  201. doAssert s == "ab"
  202. delete(s, 0..0)
  203. doAssert s == "b"
  204. block: # delete(first, last)
  205. {.push warning[deprecated]:off.}
  206. var s = "0123456789ABCDEFGH"
  207. delete(s, 4, 5)
  208. doAssert s == "01236789ABCDEFGH"
  209. delete(s, s.len-1, s.len-1)
  210. doAssert s == "01236789ABCDEFG"
  211. delete(s, 0, 0)
  212. doAssert s == "1236789ABCDEFG"
  213. {.pop.}
  214. block: # find
  215. const haystack: string = "0123456789ABCDEFGH"
  216. doAssert haystack.find('A') == 10
  217. doAssert haystack.find('A', 5) == 10
  218. doAssert haystack.find('A', 5, 10) == 10
  219. doAssert haystack.find('A', 5, 9) == -1
  220. doAssert haystack.find("A") == 10
  221. doAssert haystack.find("A", 5) == 10
  222. doAssert haystack.find("A", 5, 10) == 10
  223. doAssert haystack.find("A", 5, 9) == -1
  224. doAssert haystack.find({'A'..'C'}) == 10
  225. doAssert haystack.find({'A'..'C'}, 5) == 10
  226. doAssert haystack.find({'A'..'C'}, 5, 10) == 10
  227. doAssert haystack.find({'A'..'C'}, 5, 9) == -1
  228. doAssert haystack.find('A', 0, 0) == -1 # search limited to the first char
  229. doAssert haystack.find('A', 5, 0) == -1 # last < start
  230. doAssert haystack.find('A', 5, 4) == -1 # last < start
  231. block:
  232. const haystack: string = "ABCABABABABCAB"
  233. doAssert haystack.len == 14
  234. # only last argument
  235. doAssert haystack.find("ABC") == 0
  236. doAssert haystack.find("ABC", last=13) == 0 # after the second ABC
  237. doAssert haystack.find("ABC", last=5) == 0 # before the second ABC
  238. # only start argument
  239. doAssert haystack.find("ABC", start=0) == 0
  240. doAssert haystack.find("ABC", start=1) == 9
  241. doAssert haystack.find("ABC", start=9) == 9
  242. doAssert haystack.find("ABC", start=10) == -1
  243. # both start and last arguments
  244. doAssert haystack.find("ABC", start=0, last=14) == 0
  245. doAssert haystack.find("ABC", start=0, last=13) == 0
  246. doAssert haystack.find("ABC", start=0, last=12) == 0
  247. doAssert haystack.find("ABC", start=1, last=13) == 9
  248. doAssert haystack.find("ABC", start=1, last=12) == 9
  249. doAssert haystack.find("ABC", start=1, last=11) == 9
  250. doAssert haystack.find("ABC", start=1, last=10) == -1
  251. doAssert "".find("/") == -1
  252. doAssert "/".find("/") == 0
  253. doAssert "/".find("//") == -1
  254. doAssert "///".find("//", start=3) == -1
  255. # searching for empty string
  256. doAssert "".find("") == 0
  257. doAssert "abc".find("") == 0
  258. doAssert "abc".find("", start=1) == 1
  259. doAssert "abc".find("", start=2) == 2
  260. doAssert "abc".find("", start=3) == 3
  261. doAssert "abc".find("", start=4) == -1
  262. doAssert "abc".find("", start=400) == -1
  263. doAssert "abc".find("", start=1, last=3) == 1
  264. doAssert "abc".find("", start=1, last=2) == 1
  265. doAssert "abc".find("", start=1, last=1) == 1
  266. doAssert "abc".find("", start=1, last=0) == 1
  267. doAssert "abc".find("", start=1, last = -1) == 1
  268. # when last <= start, searching for non-empty string
  269. block:
  270. let last: int = -1 # searching through whole line
  271. doAssert "abcd".find("ab", start=0, last=last) == 0
  272. doAssert "abcd".find("ab", start=1, last=last) == -1
  273. doAssert "abcd".find("bc", start=1, last=last) == 1
  274. doAssert "abcd".find("bc", start=2, last=last) == -1
  275. block:
  276. let last: int = 0
  277. doAssert "abcd".find("ab", start=0, last=last) == -1
  278. doAssert "abcd".find("ab", start=1, last=last) == -1
  279. doAssert "abcd".find("bc", start=1, last=last) == -1
  280. doAssert "abcd".find("bc", start=2, last=last) == -1
  281. block:
  282. let last: int = 1
  283. doAssert "abcd".find("ab", start=0, last=last) == 0
  284. doAssert "abcd".find("ab", start=1, last=last) == -1
  285. doAssert "abcd".find("bc", start=1, last=last) == -1
  286. doAssert "abcd".find("bc", start=2, last=last) == -1
  287. block: # rfind
  288. doAssert "0123456789ABCDEFGAH".rfind('A') == 17
  289. doAssert "0123456789ABCDEFGAH".rfind('A', last=13) == 10
  290. doAssert "0123456789ABCDEFGAH".rfind('H', last=13) == -1
  291. doAssert "0123456789ABCDEFGAH".rfind("A") == 17
  292. doAssert "0123456789ABCDEFGAH".rfind("A", last=13) == 10
  293. doAssert "0123456789ABCDEFGAH".rfind("H", last=13) == -1
  294. doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17
  295. doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12
  296. doAssert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1
  297. doAssert "0123456789ABCDEFGAH".rfind('A', start=18) == -1
  298. doAssert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17
  299. doAssert "0123456789ABCDEFGAH".rfind("0", start=0) == 0
  300. doAssert "0123456789ABCDEFGAH".rfind("0", start=1) == -1
  301. doAssert "0123456789ABCDEFGAH".rfind("H", start=11) == 18
  302. doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9
  303. doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1
  304. doAssert "/1/2/3".rfind('/') == 4
  305. doAssert "/1/2/3".rfind('/', last=1) == 0
  306. doAssert "/1/2/3".rfind('0') == -1
  307. block:
  308. const haystack: string = "ABCABABABABCAB"
  309. doAssert haystack.len == 14
  310. doAssert haystack.rfind("ABC") == 9
  311. doAssert haystack.rfind("ABC", last=13) == 9
  312. doAssert haystack.rfind("ABC", last=12) == 9
  313. doAssert haystack.rfind("ABC", last=11) == 9
  314. doAssert haystack.rfind("ABC", last=10) == 0
  315. doAssert haystack.rfind("ABC", start=0) == 9
  316. doAssert haystack.rfind("ABC", start=1) == 9
  317. doAssert haystack.rfind("ABC", start=9) == 9
  318. doAssert haystack.rfind("ABC", start=10) == -1
  319. doAssert haystack.rfind("ABC", start=0, last=13) == 9
  320. doAssert haystack.rfind("ABC", start=0, last=12) == 9
  321. doAssert haystack.rfind("ABC", start=0, last=11) == 9
  322. doAssert haystack.rfind("ABC", start=0, last=10) == 0
  323. doAssert haystack.rfind("ABC", start=1, last=10) == -1
  324. doAssert "".rfind("/") == -1
  325. doAssert "/".rfind("/") == 0
  326. doAssert "/".rfind("//") == -1
  327. doAssert "///".rfind("//", start=3) == -1
  328. # searching for empty string
  329. doAssert "".rfind("") == 0
  330. doAssert "abc".rfind("") == 3
  331. doAssert "abc".rfind("", start=1) == 3
  332. doAssert "abc".rfind("", start=2) == 3
  333. doAssert "abc".rfind("", start=3) == 3
  334. doAssert "abc".rfind("", start=4) == 4
  335. doAssert "abc".rfind("", start=400) == 400
  336. doAssert "abc".rfind("", start=1, last=3) == 3
  337. doAssert "abc".rfind("", start=1, last=2) == 2
  338. doAssert "abc".rfind("", start=1, last=1) == 1
  339. # This returns the start index instead of the last index
  340. # because start > last
  341. doAssert "abc".rfind("", start=1, last=0) == 1
  342. doAssert "abc".rfind("", start=1, last = -1) == 3
  343. doAssert "abc".rfind("", start=0, last=0) == 0
  344. # when last <= start, searching for non-empty string
  345. block:
  346. let last: int = -1
  347. doAssert "abcd".rfind("ab", start=0, last=last) == 0
  348. doAssert "abcd".rfind("ab", start=1, last=last) == -1
  349. doAssert "abcd".rfind("bc", start=1, last=last) == 1
  350. doAssert "abcd".rfind("bc", start=2, last=last) == -1
  351. block:
  352. let last: int = 0
  353. doAssert "abcd".rfind("ab", start=0, last=last) == -1
  354. doAssert "abcd".rfind("ab", start=1, last=last) == -1
  355. doAssert "abcd".rfind("bc", start=1, last=last) == -1
  356. doAssert "abcd".rfind("bc", start=2, last=last) == -1
  357. block:
  358. let last: int = 1
  359. doAssert "abcd".rfind("ab", start=0, last=last) == 0
  360. doAssert "abcd".rfind("ab", start=1, last=last) == -1
  361. doAssert "abcd".rfind("bc", start=1, last=last) == -1
  362. doAssert "abcd".rfind("bc", start=2, last=last) == -1
  363. block: # trimZeros
  364. var x = "1200"
  365. x.trimZeros()
  366. doAssert x == "1200"
  367. x = "120.0"
  368. x.trimZeros()
  369. doAssert x == "120"
  370. x = "0."
  371. x.trimZeros()
  372. doAssert x == "0"
  373. x = "1.0e2"
  374. x.trimZeros()
  375. doAssert x == "1e2"
  376. x = "78.90"
  377. x.trimZeros()
  378. doAssert x == "78.9"
  379. x = "1.23e4"
  380. x.trimZeros()
  381. doAssert x == "1.23e4"
  382. x = "1.01"
  383. x.trimZeros()
  384. doAssert x == "1.01"
  385. x = "1.1001"
  386. x.trimZeros()
  387. doAssert x == "1.1001"
  388. x = "0.0"
  389. x.trimZeros()
  390. doAssert x == "0"
  391. x = "0.01"
  392. x.trimZeros()
  393. doAssert x == "0.01"
  394. x = "1e0"
  395. x.trimZeros()
  396. doAssert x == "1e0"
  397. x = "1.23"
  398. x.trimZeros()
  399. doAssert x == "1.23"
  400. block: # countLines
  401. proc assertCountLines(s: string) = doAssert s.countLines == s.splitLines.len
  402. assertCountLines("")
  403. assertCountLines("\n")
  404. assertCountLines("\n\n")
  405. assertCountLines("abc")
  406. assertCountLines("abc\n123")
  407. assertCountLines("abc\n123\n")
  408. assertCountLines("\nabc\n123")
  409. assertCountLines("\nabc\n123\n")
  410. block: # parseBinInt, parseHexInt, parseOctInt
  411. # binary
  412. doAssert "0b1111".parseBinInt == 15
  413. doAssert "0B1111".parseBinInt == 15
  414. doAssert "1111".parseBinInt == 15
  415. doAssert "1110".parseBinInt == 14
  416. doAssert "1_1_1_1".parseBinInt == 15
  417. doAssert "0b1_1_1_1".parseBinInt == 15
  418. rejectParse "".parseBinInt
  419. rejectParse "_".parseBinInt
  420. rejectParse "0b".parseBinInt
  421. rejectParse "0b1234".parseBinInt
  422. # hex
  423. doAssert "0x72".parseHexInt == 114
  424. doAssert "0X72".parseHexInt == 114
  425. doAssert "#72".parseHexInt == 114
  426. doAssert "72".parseHexInt == 114
  427. doAssert "FF".parseHexInt == 255
  428. doAssert "ff".parseHexInt == 255
  429. doAssert "fF".parseHexInt == 255
  430. doAssert "0x7_2".parseHexInt == 114
  431. rejectParse "".parseHexInt
  432. rejectParse "_".parseHexInt
  433. rejectParse "0x".parseHexInt
  434. rejectParse "0xFFG".parseHexInt
  435. rejectParse "reject".parseHexInt
  436. # octal
  437. doAssert "0o17".parseOctInt == 15
  438. doAssert "0O17".parseOctInt == 15
  439. doAssert "17".parseOctInt == 15
  440. doAssert "10".parseOctInt == 8
  441. doAssert "0o1_0_0".parseOctInt == 64
  442. rejectParse "".parseOctInt
  443. rejectParse "_".parseOctInt
  444. rejectParse "0o".parseOctInt
  445. rejectParse "9".parseOctInt
  446. rejectParse "0o9".parseOctInt
  447. rejectParse "reject".parseOctInt
  448. block: # parseHexStr
  449. doAssert "".parseHexStr == ""
  450. doAssert "00Ff80".parseHexStr == "\0\xFF\x80"
  451. try:
  452. discard "00Ff8".parseHexStr
  453. doAssert false, "Should raise ValueError"
  454. except ValueError:
  455. discard
  456. try:
  457. discard "0k".parseHexStr
  458. doAssert false, "Should raise ValueError"
  459. except ValueError:
  460. discard
  461. doAssert "".toHex == ""
  462. doAssert "\x00\xFF\x80".toHex == "00FF80"
  463. doAssert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF"
  464. block: # toHex
  465. doAssert(toHex(100i16, 32) == "00000000000000000000000000000064")
  466. doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
  467. whenJsNoBigInt64: discard
  468. do:
  469. doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF")
  470. doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF")
  471. doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF")
  472. block: # insertSep
  473. doAssert(insertSep($1000_000) == "1_000_000")
  474. doAssert(insertSep($232) == "232")
  475. doAssert(insertSep($12345, ',') == "12,345")
  476. doAssert(insertSep($0) == "0")
  477. block: # repeat, spaces
  478. doAssert(' '.repeat(8) == " ")
  479. doAssert(" ".repeat(8) == " ")
  480. doAssert(spaces(8) == " ")
  481. doAssert(' '.repeat(0) == "")
  482. doAssert(" ".repeat(0) == "")
  483. doAssert(spaces(0) == "")
  484. block: # toBin, toOct
  485. whenJsNoBigInt64: # bug #11369
  486. discard
  487. do:
  488. var num: int64 = -1
  489. doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111"
  490. doAssert num.toOct(24) == "001777777777777777777777"
  491. block: # replace
  492. doAssert "oo".replace("", "abc") == "oo"
  493. # bug #8911
  494. static:
  495. let a = ""
  496. let a2 = a.replace("\n", "\\n")
  497. static:
  498. let b = "b"
  499. let b2 = b.replace("\n", "\\n")
  500. block:
  501. let c = ""
  502. let c2 = c.replace("\n", "\\n")
  503. block: # replaceWord
  504. doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
  505. doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
  506. doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
  507. block: # multiReplace
  508. doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
  509. doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.",
  510. "PEOPLE!")) == "HELLO PEOPLE!"
  511. doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
  512. # `parseEnum`, ref issue #14030
  513. # check enum defined at top level # xxx this is probably irrelevant, and pollutes scope
  514. # for remaining tests
  515. type
  516. Foo = enum
  517. A = -10
  518. B = "bb"
  519. C = (-5, "ccc")
  520. D = 15
  521. E = "ee" # check that we count enum fields correctly
  522. block: # parseEnum
  523. block:
  524. let a = parseEnum[Foo]("A")
  525. let b = parseEnum[Foo]("bb")
  526. let c = parseEnum[Foo]("ccc")
  527. let d = parseEnum[Foo]("D")
  528. let e = parseEnum[Foo]("ee")
  529. doAssert a == A
  530. doAssert b == B
  531. doAssert c == C
  532. doAssert d == D
  533. doAssert e == E
  534. try:
  535. let f = parseEnum[Foo]("Bar")
  536. doAssert false
  537. except ValueError:
  538. discard
  539. # finally using default
  540. let g = parseEnum[Foo]("Bar", A)
  541. doAssert g == A
  542. block: # bug #19463
  543. const CAMPAIGN_TABLE = "wikientries_campaign"
  544. const CHARACTER_TABLE = "wikientries_character"
  545. type Tables = enum
  546. a = CAMPAIGN_TABLE,
  547. b = CHARACTER_TABLE,
  548. let myA = CAMPAIGN_TABLE
  549. doAssert $parseEnum[Tables](myA) == "wikientries_campaign"
  550. block: # check enum defined in block
  551. type
  552. Bar = enum
  553. V
  554. W = "ww"
  555. X = (3, "xx")
  556. Y = 10
  557. Z = "zz" # check that we count enum fields correctly
  558. let a = parseEnum[Bar]("V")
  559. let b = parseEnum[Bar]("ww")
  560. let c = parseEnum[Bar]("xx")
  561. let d = parseEnum[Bar]("Y")
  562. let e = parseEnum[Bar]("zz")
  563. doAssert a == V
  564. doAssert b == W
  565. doAssert c == X
  566. doAssert d == Y
  567. doAssert e == Z
  568. try:
  569. let f = parseEnum[Bar]("Baz")
  570. doAssert false
  571. except ValueError:
  572. discard
  573. # finally using default
  574. let g = parseEnum[Bar]("Baz", V)
  575. doAssert g == V
  576. block: # check ambiguous enum fails to parse
  577. type
  578. Ambig = enum
  579. f1 = "A"
  580. f2 = "B"
  581. f3 = "A"
  582. doAssert not compiles((let a = parseEnum[Ambig]("A")))
  583. block: # check almost ambiguous enum
  584. type
  585. AlmostAmbig = enum
  586. f1 = "someA"
  587. f2 = "someB"
  588. f3 = "SomeA"
  589. let a = parseEnum[AlmostAmbig]("someA")
  590. let b = parseEnum[AlmostAmbig]("someB")
  591. let c = parseEnum[AlmostAmbig]("SomeA")
  592. doAssert a == f1
  593. doAssert b == f2
  594. doAssert c == f3
  595. block: # parseEnum TODO: merge above
  596. type MyEnum = enum enA, enB, enC, enuD, enE
  597. doAssert parseEnum[MyEnum]("enu_D") == enuD
  598. doAssert parseEnum("invalid enum value", enC) == enC
  599. block: # indentation
  600. doAssert 0 == indentation """
  601. hey
  602. low
  603. there
  604. """
  605. doAssert 2 == indentation """
  606. hey
  607. low
  608. there
  609. """
  610. doAssert 2 == indentation """ hey
  611. low
  612. there
  613. """
  614. doAssert 2 == indentation """ hey
  615. low
  616. there"""
  617. doAssert 0 == indentation ""
  618. doAssert 0 == indentation " \n \n"
  619. doAssert 0 == indentation " "
  620. block: # indent
  621. doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar"
  622. block: # unindent
  623. doAssert """~~!!foo
  624. ~~!!bar
  625. ~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
  626. doAssert """~~!!foo
  627. ~~!!bar
  628. ~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
  629. doAssert """~~foo
  630. ~~ bar
  631. ~~ baz""".unindent(4, "~") == "foo\n bar\n baz"
  632. doAssert """foo
  633. bar
  634. baz
  635. """.unindent(4) == "foo\nbar\nbaz\n"
  636. doAssert """foo
  637. bar
  638. baz
  639. """.unindent(2) == "foo\n bar\n baz\n"
  640. doAssert """foo
  641. bar
  642. baz
  643. """.unindent(100) == "foo\nbar\nbaz\n"
  644. doAssert """foo
  645. foo
  646. bar
  647. """.unindent() == "foo\nfoo\nbar\n"
  648. block: # formatBiggestFloat
  649. disableVm:
  650. doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
  651. when not defined(js):
  652. doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586
  653. doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
  654. doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
  655. doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
  656. ["1,0e-11", "1,0e-011"]
  657. block: # formatFloat
  658. disableVm:
  659. # bug #6589
  660. when not defined(js):
  661. doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
  662. block: # `%`
  663. doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
  664. doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
  665. doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
  666. "The cat eats fish."
  667. block: # formatSize
  668. disableVm:
  669. whenJsNoBigInt64: discard
  670. do:
  671. doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231
  672. doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
  673. doAssert formatSize(4096) == "4KiB"
  674. doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB"
  675. doAssert formatSize(4096, includeSpace = true) == "4 KiB"
  676. doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB"
  677. block: # formatEng
  678. disableVm:
  679. doAssert formatEng(0, 2, trim = false) == "0.00"
  680. doAssert formatEng(0, 2) == "0"
  681. doAssert formatEng(53, 2, trim = false) == "53.00"
  682. doAssert formatEng(0.053, 2, trim = false) == "53.00e-3"
  683. doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3"
  684. doAssert formatEng(0.053, 4, trim = true) == "53e-3"
  685. doAssert formatEng(0.053, 0) == "53e-3"
  686. doAssert formatEng(52731234) == "52.731234e6"
  687. doAssert formatEng(-52731234) == "-52.731234e6"
  688. doAssert formatEng(52731234, 1) == "52.7e6"
  689. doAssert formatEng(-52731234, 1) == "-52.7e6"
  690. doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6"
  691. doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6"
  692. doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV"
  693. doAssert formatEng(4.1, siPrefix = true, unit = "V",
  694. useUnitSpace = true) == "4.1 V"
  695. doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space
  696. doAssert formatEng(4100, siPrefix = true) == "4.1 k"
  697. doAssert formatEng(4.1, siPrefix = true, unit = "",
  698. useUnitSpace = true) == "4.1 " # Includes space
  699. doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k"
  700. doAssert formatEng(4100) == "4.1e3"
  701. doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V"
  702. doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 "
  703. # Don't use SI prefix as number is too big
  704. doAssert formatEng(3.1e22, siPrefix = true, unit = "a",
  705. useUnitSpace = true) == "31e21 a"
  706. # Don't use SI prefix as number is too small
  707. doAssert formatEng(3.1e-25, siPrefix = true, unit = "A",
  708. useUnitSpace = true) == "310e-27 A"
  709. block: # align
  710. doAssert align("abc", 4) == " abc"
  711. doAssert align("a", 0) == "a"
  712. doAssert align("1232", 6) == " 1232"
  713. doAssert align("1232", 6, '#') == "##1232"
  714. block: # alignLeft
  715. doAssert alignLeft("abc", 4) == "abc "
  716. doAssert alignLeft("a", 0) == "a"
  717. doAssert alignLeft("1232", 6) == "1232 "
  718. doAssert alignLeft("1232", 6, '#') == "1232##"
  719. block: # center
  720. doAssert center("foo", 13) == " foo "
  721. doAssert center("foo", 0) == "foo"
  722. doAssert center("foo", 3, fillChar = 'a') == "foo"
  723. doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
  724. block: # count
  725. doAssert count("foofoofoo", "foofoo") == 1
  726. doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
  727. doAssert count("foofoofoo", 'f') == 3
  728. doAssert count("foofoofoobar", {'f', 'b'}) == 4
  729. block: # isAlphaAscii
  730. doAssert isAlphaAscii('r')
  731. doAssert isAlphaAscii('A')
  732. doAssert(not isAlphaAscii('$'))
  733. block: # isAlphaNumeric
  734. doAssert isAlphaNumeric('3')
  735. doAssert isAlphaNumeric('R')
  736. doAssert(not isAlphaNumeric('!'))
  737. block: # isDigit
  738. doAssert isDigit('3')
  739. doAssert(not isDigit('a'))
  740. doAssert(not isDigit('%'))
  741. block: # isSpaceAscii
  742. doAssert isSpaceAscii('\t')
  743. doAssert isSpaceAscii('\l')
  744. doAssert(not isSpaceAscii('A'))
  745. block: # isEmptyOrWhitespace
  746. doAssert(isEmptyOrWhitespace(""))
  747. doAssert(isEmptyOrWhitespace(" "))
  748. doAssert(isEmptyOrWhitespace("\t\l \v\r\f"))
  749. doAssert(not isEmptyOrWhitespace("ABc \td"))
  750. block: # isLowerAscii
  751. doAssert isLowerAscii('a')
  752. doAssert isLowerAscii('z')
  753. doAssert(not isLowerAscii('A'))
  754. doAssert(not isLowerAscii('5'))
  755. doAssert(not isLowerAscii('&'))
  756. doAssert(not isLowerAscii(' '))
  757. block: # isUpperAscii
  758. doAssert isUpperAscii('A')
  759. doAssert(not isUpperAscii('b'))
  760. doAssert(not isUpperAscii('5'))
  761. doAssert(not isUpperAscii('%'))
  762. block: # unescape
  763. doAssert(unescape(r"\x013", "", "") == "\x013")
  764. block: # join
  765. doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
  766. doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
  767. doAssert join([1, 2, 3]) == "123"
  768. doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
  769. block: # startsWith / endsWith
  770. var s = "abcdef"
  771. doAssert s.startsWith('a')
  772. doAssert s.startsWith('b') == false
  773. doAssert s.endsWith('f')
  774. doAssert s.endsWith('a') == false
  775. doAssert s.endsWith('\0') == false
  776. block: # nimIdentNormalize
  777. doAssert nimIdentNormalize("") == ""
  778. doAssert nimIdentNormalize("foo") == "foo"
  779. doAssert nimIdentNormalize("foo_bar") == "foobar"
  780. doAssert nimIdentNormalize("Foo_bar") == "Foobar"
  781. doAssert nimIdentNormalize("_Foo_bar") == "_foobar"
  782. block: # bug #19500
  783. doAssert "abc \0 def".find("def") == 6
  784. doAssert "abc \0 def".find('d') == 6
  785. static: main()
  786. main()