mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 09:24:36 +00:00
This is a rebase of an earlier rejected PR. Following the discussion
around it, this commit provides a valid output for and edge case
of an empty separator for `split` and `rsplit` routines. The empty
separator is interpreted as "split by no separators" and the initial
string is returned. This is consistent with the behaviour of the
`set[char]` version of `split`/`rsplit` routines and unifies them all.
Compared to a commit merged earlier, this one has a benefit of
not using assertions that will be removed in release builds
and thus still not preventing possible infinite loops (which was the
earlier behaviour for this edge case for separator of type `string`).
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 5e529b3bfa)
871 lines
27 KiB
Nim
871 lines
27 KiB
Nim
discard """
|
|
targets: "c cpp js"
|
|
"""
|
|
|
|
import std/strutils
|
|
from stdtest/testutils import disableVm
|
|
# xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed
|
|
|
|
template rejectParse(e) =
|
|
try:
|
|
discard e
|
|
raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e))
|
|
except ValueError: discard
|
|
|
|
template main() =
|
|
block: # strip
|
|
doAssert strip(" ha ") == "ha"
|
|
doAssert strip(" foofoofoo ") == "foofoofoo"
|
|
doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
|
|
doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
|
|
doAssert strip("stripme but don't strip this stripme",
|
|
chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
|
|
" but don't strip this "
|
|
doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
|
|
doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
|
|
|
|
block:
|
|
let a = "xxxxxx"
|
|
doAssert a.strip(chars={'x'}).len == 0
|
|
|
|
doAssert "".strip(chars={'x'}).len == 0
|
|
doAssert " ".strip(chars={'x'}) == " "
|
|
doAssert "xxx xxx".strip(chars={'x'}) == " "
|
|
doAssert "xxx wind".strip(chars={'x'}) == " wind"
|
|
doAssert "xxx iii".strip(chars={'i'}) == "xxx "
|
|
doAssert "x".strip(leading = false, chars={'x'}).len == 0
|
|
doAssert "x".strip(trailing = false, chars={'x'}).len == 0
|
|
doAssert "x".strip(leading = false, trailing = false, chars={'x'}) == "x"
|
|
|
|
block: # split
|
|
var ret: seq[string] # or use `toSeq` or `collect`
|
|
for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p
|
|
doAssert ret == @["/home/a1", "xyz", "/usr/bin"]
|
|
|
|
let s = " this is an example "
|
|
let s2 = ":this;is;an:example;;"
|
|
|
|
doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
|
|
doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example",
|
|
"", ""]
|
|
doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "]
|
|
doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "]
|
|
doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "]
|
|
# Empty string:
|
|
doAssert "".split() == @[""]
|
|
doAssert "".split(" ") == @[""]
|
|
doAssert "".split({' '}) == @[""]
|
|
# Empty separators:
|
|
doAssert "".split({}) == @[""]
|
|
doAssert "".split("") == @[""]
|
|
doAssert s.split({}) == @[s]
|
|
doAssert s.split("") == @[s]
|
|
|
|
block: # splitLines
|
|
let fixture = "a\nb\rc\r\nd"
|
|
doAssert len(fixture.splitLines) == 4
|
|
doAssert splitLines(fixture) == @["a", "b", "c", "d"]
|
|
doAssert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"]
|
|
|
|
block: # rsplit
|
|
doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"]
|
|
doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"]
|
|
doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[" foo bar", ""]
|
|
doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"]
|
|
doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"]
|
|
doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"]
|
|
doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"]
|
|
# Empty string:
|
|
doAssert "".rsplit() == @[""]
|
|
doAssert "".rsplit(" ") == @[""]
|
|
doAssert "".rsplit({' '}) == @[""]
|
|
# Empty separators:
|
|
let s = " this is an example "
|
|
doAssert "".rsplit({}) == @[""]
|
|
doAssert "".rsplit("") == @[""]
|
|
doAssert s.rsplit({}) == @[s]
|
|
doAssert s.rsplit("") == @[s]
|
|
|
|
block: # splitWhitespace
|
|
let s = " this is an example "
|
|
doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
|
|
doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example "]
|
|
doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example "]
|
|
doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example "]
|
|
doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"]
|
|
|
|
block: # removeSuffix
|
|
var s = "hello\n\r"
|
|
s.removeSuffix
|
|
doAssert s == "hello"
|
|
s.removeSuffix
|
|
doAssert s == "hello"
|
|
|
|
s = "hello\n\n"
|
|
s.removeSuffix
|
|
doAssert s == "hello"
|
|
|
|
s = "hello\r"
|
|
s.removeSuffix
|
|
doAssert s == "hello"
|
|
|
|
s = "hello \n there"
|
|
s.removeSuffix
|
|
doAssert s == "hello \n there"
|
|
|
|
s = "hello"
|
|
s.removeSuffix("llo")
|
|
doAssert s == "he"
|
|
s.removeSuffix('e')
|
|
doAssert s == "h"
|
|
|
|
s = "hellos"
|
|
s.removeSuffix({'s','z'})
|
|
doAssert s == "hello"
|
|
s.removeSuffix({'l','o'})
|
|
doAssert s == "he"
|
|
|
|
s = "aeiou"
|
|
s.removeSuffix("")
|
|
doAssert s == "aeiou"
|
|
|
|
s = ""
|
|
s.removeSuffix("")
|
|
doAssert s == ""
|
|
|
|
s = " "
|
|
s.removeSuffix
|
|
doAssert s == " "
|
|
|
|
s = " "
|
|
s.removeSuffix("")
|
|
doAssert s == " "
|
|
|
|
s = " "
|
|
s.removeSuffix(" ")
|
|
doAssert s == " "
|
|
|
|
s = " "
|
|
s.removeSuffix(' ')
|
|
doAssert s == ""
|
|
|
|
# Contrary to Chomp in other languages
|
|
# empty string does not change behaviour
|
|
s = "hello\r\n\r\n"
|
|
s.removeSuffix("")
|
|
doAssert s == "hello\r\n\r\n"
|
|
|
|
block: # removePrefix
|
|
var s = "\n\rhello"
|
|
s.removePrefix
|
|
doAssert s == "hello"
|
|
s.removePrefix
|
|
doAssert s == "hello"
|
|
|
|
s = "\n\nhello"
|
|
s.removePrefix
|
|
doAssert s == "hello"
|
|
|
|
s = "\rhello"
|
|
s.removePrefix
|
|
doAssert s == "hello"
|
|
|
|
s = "hello \n there"
|
|
s.removePrefix
|
|
doAssert s == "hello \n there"
|
|
|
|
s = "hello"
|
|
s.removePrefix("hel")
|
|
doAssert s == "lo"
|
|
s.removePrefix('l')
|
|
doAssert s == "o"
|
|
|
|
s = "hellos"
|
|
s.removePrefix({'h','e'})
|
|
doAssert s == "llos"
|
|
s.removePrefix({'l','o'})
|
|
doAssert s == "s"
|
|
|
|
s = "aeiou"
|
|
s.removePrefix("")
|
|
doAssert s == "aeiou"
|
|
|
|
s = ""
|
|
s.removePrefix("")
|
|
doAssert s == ""
|
|
|
|
s = " "
|
|
s.removePrefix
|
|
doAssert s == " "
|
|
|
|
s = " "
|
|
s.removePrefix("")
|
|
doAssert s == " "
|
|
|
|
s = " "
|
|
s.removePrefix(" ")
|
|
doAssert s == " "
|
|
|
|
s = " "
|
|
s.removePrefix(' ')
|
|
doAssert s == ""
|
|
|
|
# Contrary to Chomp in other languages
|
|
# empty string does not change behaviour
|
|
s = "\r\n\r\nhello"
|
|
s.removePrefix("")
|
|
doAssert s == "\r\n\r\nhello"
|
|
|
|
block: # delete(slice)
|
|
var s = "0123456789ABCDEFGH"
|
|
delete(s, 4 .. 5)
|
|
doAssert s == "01236789ABCDEFGH"
|
|
delete(s, s.len-1 .. s.len-1)
|
|
doAssert s == "01236789ABCDEFG"
|
|
delete(s, 0..0)
|
|
doAssert s == "1236789ABCDEFG"
|
|
s = ""
|
|
doAssertRaises(IndexDefect): delete(s, 0..0)
|
|
doAssert s == ""
|
|
s = "abc"
|
|
doAssertRaises(IndexDefect): delete(s, -1 .. -2)
|
|
doAssertRaises(IndexDefect): delete(s, 2..3)
|
|
doAssertRaises(IndexDefect): delete(s, 3..2)
|
|
delete(s, 2..2)
|
|
doAssert s == "ab"
|
|
delete(s, 1..0)
|
|
doAssert s == "ab"
|
|
delete(s, 0..0)
|
|
doAssert s == "b"
|
|
|
|
block: # delete(first, last)
|
|
{.push warning[deprecated]:off.}
|
|
var s = "0123456789ABCDEFGH"
|
|
delete(s, 4, 5)
|
|
doAssert s == "01236789ABCDEFGH"
|
|
delete(s, s.len-1, s.len-1)
|
|
doAssert s == "01236789ABCDEFG"
|
|
delete(s, 0, 0)
|
|
doAssert s == "1236789ABCDEFG"
|
|
{.pop.}
|
|
|
|
block: # find
|
|
doAssert "0123456789ABCDEFGH".find('A') == 10
|
|
doAssert "0123456789ABCDEFGH".find('A', 5) == 10
|
|
doAssert "0123456789ABCDEFGH".find('A', 5, 10) == 10
|
|
doAssert "0123456789ABCDEFGH".find('A', 5, 9) == -1
|
|
doAssert "0123456789ABCDEFGH".find("A") == 10
|
|
doAssert "0123456789ABCDEFGH".find("A", 5) == 10
|
|
doAssert "0123456789ABCDEFGH".find("A", 5, 10) == 10
|
|
doAssert "0123456789ABCDEFGH".find("A", 5, 9) == -1
|
|
doAssert "0123456789ABCDEFGH".find({'A'..'C'}) == 10
|
|
doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10
|
|
doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10
|
|
doAssert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1
|
|
|
|
block:
|
|
const haystack: string = "ABCABABABABCAB"
|
|
doAssert haystack.len == 14
|
|
|
|
# only last argument
|
|
doAssert haystack.find("ABC") == 0
|
|
doAssert haystack.find("ABC", last=13) == 0 # after the second ABC
|
|
doAssert haystack.find("ABC", last=5) == 0 # before the second ABC
|
|
|
|
# only start argument
|
|
doAssert haystack.find("ABC", start=0) == 0
|
|
doAssert haystack.find("ABC", start=1) == 9
|
|
doAssert haystack.find("ABC", start=9) == 9
|
|
doAssert haystack.find("ABC", start=10) == -1
|
|
|
|
# both start and last arguments
|
|
doAssert haystack.find("ABC", start=0, last=14) == 0
|
|
doAssert haystack.find("ABC", start=0, last=13) == 0
|
|
doAssert haystack.find("ABC", start=0, last=12) == 0
|
|
doAssert haystack.find("ABC", start=1, last=13) == 9
|
|
doAssert haystack.find("ABC", start=1, last=12) == 9
|
|
doAssert haystack.find("ABC", start=1, last=11) == 9
|
|
doAssert haystack.find("ABC", start=1, last=10) == -1
|
|
|
|
doAssert "".find("/") == -1
|
|
doAssert "/".find("/") == 0
|
|
doAssert "/".find("//") == -1
|
|
doAssert "///".find("//", start=3) == -1
|
|
|
|
# searching for empty string
|
|
doAssert "".find("") == 0
|
|
doAssert "abc".find("") == 0
|
|
doAssert "abc".find("", start=1) == 1
|
|
doAssert "abc".find("", start=2) == 2
|
|
doAssert "abc".find("", start=3) == 3
|
|
doAssert "abc".find("", start=4) == -1
|
|
doAssert "abc".find("", start=400) == -1
|
|
doAssert "abc".find("", start=1, last=3) == 1
|
|
doAssert "abc".find("", start=1, last=2) == 1
|
|
doAssert "abc".find("", start=1, last=1) == 1
|
|
doAssert "abc".find("", start=1, last=0) == 1
|
|
doAssert "abc".find("", start=1, last = -1) == 1
|
|
|
|
# when last <= start, searching for non-empty string
|
|
block:
|
|
let last: int = -1
|
|
doAssert "abcd".find("ab", start=0, last=last) == -1
|
|
doAssert "abcd".find("ab", start=1, last=last) == -1
|
|
doAssert "abcd".find("bc", start=1, last=last) == -1
|
|
doAssert "abcd".find("bc", start=2, last=last) == -1
|
|
block:
|
|
let last: int = 0
|
|
doAssert "abcd".find("ab", start=0, last=last) == 0
|
|
doAssert "abcd".find("ab", start=1, last=last) == -1
|
|
doAssert "abcd".find("bc", start=1, last=last) == 1
|
|
doAssert "abcd".find("bc", start=2, last=last) == -1
|
|
block:
|
|
let last: int = 1
|
|
doAssert "abcd".find("ab", start=0, last=last) == 0
|
|
doAssert "abcd".find("ab", start=1, last=last) == -1
|
|
doAssert "abcd".find("bc", start=1, last=last) == -1
|
|
doAssert "abcd".find("bc", start=2, last=last) == -1
|
|
|
|
block: # rfind
|
|
doAssert "0123456789ABCDEFGAH".rfind('A') == 17
|
|
doAssert "0123456789ABCDEFGAH".rfind('A', last=13) == 10
|
|
doAssert "0123456789ABCDEFGAH".rfind('H', last=13) == -1
|
|
doAssert "0123456789ABCDEFGAH".rfind("A") == 17
|
|
doAssert "0123456789ABCDEFGAH".rfind("A", last=13) == 10
|
|
doAssert "0123456789ABCDEFGAH".rfind("H", last=13) == -1
|
|
doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17
|
|
doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12
|
|
doAssert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1
|
|
doAssert "0123456789ABCDEFGAH".rfind('A', start=18) == -1
|
|
doAssert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17
|
|
doAssert "0123456789ABCDEFGAH".rfind("0", start=0) == 0
|
|
doAssert "0123456789ABCDEFGAH".rfind("0", start=1) == -1
|
|
doAssert "0123456789ABCDEFGAH".rfind("H", start=11) == 18
|
|
doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9
|
|
doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1
|
|
|
|
doAssert "/1/2/3".rfind('/') == 4
|
|
doAssert "/1/2/3".rfind('/', last=1) == 0
|
|
doAssert "/1/2/3".rfind('0') == -1
|
|
|
|
block:
|
|
const haystack: string = "ABCABABABABCAB"
|
|
doAssert haystack.len == 14
|
|
doAssert haystack.rfind("ABC") == 9
|
|
doAssert haystack.rfind("ABC", last=13) == 9
|
|
doAssert haystack.rfind("ABC", last=12) == 9
|
|
doAssert haystack.rfind("ABC", last=11) == 9
|
|
doAssert haystack.rfind("ABC", last=10) == 0
|
|
|
|
doAssert haystack.rfind("ABC", start=0) == 9
|
|
doAssert haystack.rfind("ABC", start=1) == 9
|
|
doAssert haystack.rfind("ABC", start=9) == 9
|
|
doAssert haystack.rfind("ABC", start=10) == -1
|
|
|
|
doAssert haystack.rfind("ABC", start=0, last=13) == 9
|
|
doAssert haystack.rfind("ABC", start=0, last=12) == 9
|
|
doAssert haystack.rfind("ABC", start=0, last=11) == 9
|
|
doAssert haystack.rfind("ABC", start=0, last=10) == 0
|
|
doAssert haystack.rfind("ABC", start=1, last=10) == -1
|
|
|
|
doAssert "".rfind("/") == -1
|
|
doAssert "/".rfind("/") == 0
|
|
doAssert "/".rfind("//") == -1
|
|
doAssert "///".rfind("//", start=3) == -1
|
|
|
|
# searching for empty string
|
|
doAssert "".rfind("") == -1
|
|
doAssert "abc".rfind("") == -1
|
|
doAssert "abc".rfind("", start=1) == -1
|
|
doAssert "abc".rfind("", start=2) == -1
|
|
doAssert "abc".rfind("", start=3) == -1
|
|
doAssert "abc".rfind("", start=4) == -1
|
|
doAssert "abc".rfind("", start=400) == -1
|
|
|
|
doAssert "abc".rfind("", start=1, last=3) == -1
|
|
doAssert "abc".rfind("", start=1, last=2) == -1
|
|
doAssert "abc".rfind("", start=1, last=1) == -1
|
|
doAssert "abc".rfind("", start=1, last=0) == -1
|
|
doAssert "abc".rfind("", start=1, last = -1) == -1
|
|
|
|
# when last <= start, searching for non-empty string
|
|
block:
|
|
let last: int = -1
|
|
doAssert "abcd".rfind("ab", start=0, last=last) == 0
|
|
doAssert "abcd".rfind("ab", start=1, last=last) == -1
|
|
doAssert "abcd".rfind("bc", start=1, last=last) == 1
|
|
doAssert "abcd".rfind("bc", start=2, last=last) == -1
|
|
block:
|
|
let last: int = 0
|
|
doAssert "abcd".rfind("ab", start=0, last=last) == -1
|
|
doAssert "abcd".rfind("ab", start=1, last=last) == -1
|
|
doAssert "abcd".rfind("bc", start=1, last=last) == -1
|
|
doAssert "abcd".rfind("bc", start=2, last=last) == -1
|
|
block:
|
|
let last: int = 1
|
|
doAssert "abcd".rfind("ab", start=0, last=last) == 0
|
|
doAssert "abcd".rfind("ab", start=1, last=last) == -1
|
|
doAssert "abcd".rfind("bc", start=1, last=last) == -1
|
|
doAssert "abcd".rfind("bc", start=2, last=last) == -1
|
|
|
|
block: # trimZeros
|
|
var x = "1200"
|
|
x.trimZeros()
|
|
doAssert x == "1200"
|
|
x = "120.0"
|
|
x.trimZeros()
|
|
doAssert x == "120"
|
|
x = "0."
|
|
x.trimZeros()
|
|
doAssert x == "0"
|
|
x = "1.0e2"
|
|
x.trimZeros()
|
|
doAssert x == "1e2"
|
|
x = "78.90"
|
|
x.trimZeros()
|
|
doAssert x == "78.9"
|
|
x = "1.23e4"
|
|
x.trimZeros()
|
|
doAssert x == "1.23e4"
|
|
x = "1.01"
|
|
x.trimZeros()
|
|
doAssert x == "1.01"
|
|
x = "1.1001"
|
|
x.trimZeros()
|
|
doAssert x == "1.1001"
|
|
x = "0.0"
|
|
x.trimZeros()
|
|
doAssert x == "0"
|
|
x = "0.01"
|
|
x.trimZeros()
|
|
doAssert x == "0.01"
|
|
x = "1e0"
|
|
x.trimZeros()
|
|
doAssert x == "1e0"
|
|
|
|
block: # countLines
|
|
proc assertCountLines(s: string) = doAssert s.countLines == s.splitLines.len
|
|
assertCountLines("")
|
|
assertCountLines("\n")
|
|
assertCountLines("\n\n")
|
|
assertCountLines("abc")
|
|
assertCountLines("abc\n123")
|
|
assertCountLines("abc\n123\n")
|
|
assertCountLines("\nabc\n123")
|
|
assertCountLines("\nabc\n123\n")
|
|
|
|
block: # parseBinInt, parseHexInt, parseOctInt
|
|
# binary
|
|
doAssert "0b1111".parseBinInt == 15
|
|
doAssert "0B1111".parseBinInt == 15
|
|
doAssert "1111".parseBinInt == 15
|
|
doAssert "1110".parseBinInt == 14
|
|
doAssert "1_1_1_1".parseBinInt == 15
|
|
doAssert "0b1_1_1_1".parseBinInt == 15
|
|
rejectParse "".parseBinInt
|
|
rejectParse "_".parseBinInt
|
|
rejectParse "0b".parseBinInt
|
|
rejectParse "0b1234".parseBinInt
|
|
# hex
|
|
doAssert "0x72".parseHexInt == 114
|
|
doAssert "0X72".parseHexInt == 114
|
|
doAssert "#72".parseHexInt == 114
|
|
doAssert "72".parseHexInt == 114
|
|
doAssert "FF".parseHexInt == 255
|
|
doAssert "ff".parseHexInt == 255
|
|
doAssert "fF".parseHexInt == 255
|
|
doAssert "0x7_2".parseHexInt == 114
|
|
rejectParse "".parseHexInt
|
|
rejectParse "_".parseHexInt
|
|
rejectParse "0x".parseHexInt
|
|
rejectParse "0xFFG".parseHexInt
|
|
rejectParse "reject".parseHexInt
|
|
# octal
|
|
doAssert "0o17".parseOctInt == 15
|
|
doAssert "0O17".parseOctInt == 15
|
|
doAssert "17".parseOctInt == 15
|
|
doAssert "10".parseOctInt == 8
|
|
doAssert "0o1_0_0".parseOctInt == 64
|
|
rejectParse "".parseOctInt
|
|
rejectParse "_".parseOctInt
|
|
rejectParse "0o".parseOctInt
|
|
rejectParse "9".parseOctInt
|
|
rejectParse "0o9".parseOctInt
|
|
rejectParse "reject".parseOctInt
|
|
|
|
block: # parseHexStr
|
|
doAssert "".parseHexStr == ""
|
|
doAssert "00Ff80".parseHexStr == "\0\xFF\x80"
|
|
try:
|
|
discard "00Ff8".parseHexStr
|
|
doAssert false, "Should raise ValueError"
|
|
except ValueError:
|
|
discard
|
|
|
|
try:
|
|
discard "0k".parseHexStr
|
|
doAssert false, "Should raise ValueError"
|
|
except ValueError:
|
|
discard
|
|
|
|
doAssert "".toHex == ""
|
|
doAssert "\x00\xFF\x80".toHex == "00FF80"
|
|
doAssert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF"
|
|
|
|
block: # toHex
|
|
doAssert(toHex(100i16, 32) == "00000000000000000000000000000064")
|
|
doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
|
|
when not defined js:
|
|
doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF")
|
|
doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF")
|
|
doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF")
|
|
|
|
block: # insertSep
|
|
doAssert(insertSep($1000_000) == "1_000_000")
|
|
doAssert(insertSep($232) == "232")
|
|
doAssert(insertSep($12345, ',') == "12,345")
|
|
doAssert(insertSep($0) == "0")
|
|
|
|
block: # repeat, spaces
|
|
doAssert(' '.repeat(8) == " ")
|
|
doAssert(" ".repeat(8) == " ")
|
|
doAssert(spaces(8) == " ")
|
|
|
|
doAssert(' '.repeat(0) == "")
|
|
doAssert(" ".repeat(0) == "")
|
|
doAssert(spaces(0) == "")
|
|
|
|
block: # toBin, toOct
|
|
block:# bug #11369
|
|
var num: int64 = -1
|
|
when not defined js:
|
|
doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111"
|
|
doAssert num.toOct(24) == "001777777777777777777777"
|
|
|
|
block: # replace
|
|
doAssert "oo".replace("", "abc") == "oo"
|
|
# bug #8911
|
|
static:
|
|
let a = ""
|
|
let a2 = a.replace("\n", "\\n")
|
|
|
|
static:
|
|
let b = "b"
|
|
let b2 = b.replace("\n", "\\n")
|
|
|
|
block:
|
|
let c = ""
|
|
let c2 = c.replace("\n", "\\n")
|
|
|
|
block: # replaceWord
|
|
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
|
|
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
|
|
doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
|
|
|
|
block: # multiReplace
|
|
doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
|
|
doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.",
|
|
"PEOPLE!")) == "HELLO PEOPLE!"
|
|
doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
|
|
|
|
# `parseEnum`, ref issue #14030
|
|
# check enum defined at top level # xxx this is probably irrelevant, and pollutes scope
|
|
# for remaining tests
|
|
type
|
|
Foo = enum
|
|
A = -10
|
|
B = "bb"
|
|
C = (-5, "ccc")
|
|
D = 15
|
|
E = "ee" # check that we count enum fields correctly
|
|
|
|
block: # parseEnum
|
|
block:
|
|
let a = parseEnum[Foo]("A")
|
|
let b = parseEnum[Foo]("bb")
|
|
let c = parseEnum[Foo]("ccc")
|
|
let d = parseEnum[Foo]("D")
|
|
let e = parseEnum[Foo]("ee")
|
|
doAssert a == A
|
|
doAssert b == B
|
|
doAssert c == C
|
|
doAssert d == D
|
|
doAssert e == E
|
|
try:
|
|
let f = parseEnum[Foo]("Bar")
|
|
doAssert false
|
|
except ValueError:
|
|
discard
|
|
|
|
# finally using default
|
|
let g = parseEnum[Foo]("Bar", A)
|
|
doAssert g == A
|
|
|
|
block: # check enum defined in block
|
|
type
|
|
Bar = enum
|
|
V
|
|
W = "ww"
|
|
X = (3, "xx")
|
|
Y = 10
|
|
Z = "zz" # check that we count enum fields correctly
|
|
|
|
let a = parseEnum[Bar]("V")
|
|
let b = parseEnum[Bar]("ww")
|
|
let c = parseEnum[Bar]("xx")
|
|
let d = parseEnum[Bar]("Y")
|
|
let e = parseEnum[Bar]("zz")
|
|
doAssert a == V
|
|
doAssert b == W
|
|
doAssert c == X
|
|
doAssert d == Y
|
|
doAssert e == Z
|
|
try:
|
|
let f = parseEnum[Bar]("Baz")
|
|
doAssert false
|
|
except ValueError:
|
|
discard
|
|
|
|
# finally using default
|
|
let g = parseEnum[Bar]("Baz", V)
|
|
doAssert g == V
|
|
|
|
block: # check ambiguous enum fails to parse
|
|
type
|
|
Ambig = enum
|
|
f1 = "A"
|
|
f2 = "B"
|
|
f3 = "A"
|
|
|
|
doAssert not compiles((let a = parseEnum[Ambig]("A")))
|
|
|
|
block: # check almost ambiguous enum
|
|
type
|
|
AlmostAmbig = enum
|
|
f1 = "someA"
|
|
f2 = "someB"
|
|
f3 = "SomeA"
|
|
|
|
let a = parseEnum[AlmostAmbig]("someA")
|
|
let b = parseEnum[AlmostAmbig]("someB")
|
|
let c = parseEnum[AlmostAmbig]("SomeA")
|
|
doAssert a == f1
|
|
doAssert b == f2
|
|
doAssert c == f3
|
|
|
|
block: # parseEnum TODO: merge above
|
|
type MyEnum = enum enA, enB, enC, enuD, enE
|
|
doAssert parseEnum[MyEnum]("enu_D") == enuD
|
|
|
|
doAssert parseEnum("invalid enum value", enC) == enC
|
|
|
|
block: # indentation
|
|
doAssert 0 == indentation """
|
|
hey
|
|
low
|
|
there
|
|
"""
|
|
doAssert 2 == indentation """
|
|
hey
|
|
low
|
|
there
|
|
"""
|
|
doAssert 2 == indentation """ hey
|
|
low
|
|
there
|
|
"""
|
|
doAssert 2 == indentation """ hey
|
|
low
|
|
there"""
|
|
doAssert 0 == indentation ""
|
|
doAssert 0 == indentation " \n \n"
|
|
doAssert 0 == indentation " "
|
|
|
|
block: # indent
|
|
doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar"
|
|
|
|
block: # unindent
|
|
doAssert """~~!!foo
|
|
~~!!bar
|
|
~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
|
|
|
|
doAssert """~~!!foo
|
|
~~!!bar
|
|
~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
|
|
doAssert """~~foo
|
|
~~ bar
|
|
~~ baz""".unindent(4, "~") == "foo\n bar\n baz"
|
|
doAssert """foo
|
|
bar
|
|
baz
|
|
""".unindent(4) == "foo\nbar\nbaz\n"
|
|
doAssert """foo
|
|
bar
|
|
baz
|
|
""".unindent(2) == "foo\n bar\n baz\n"
|
|
doAssert """foo
|
|
bar
|
|
baz
|
|
""".unindent(100) == "foo\nbar\nbaz\n"
|
|
|
|
doAssert """foo
|
|
foo
|
|
bar
|
|
""".unindent() == "foo\nfoo\nbar\n"
|
|
|
|
block: # formatBiggestFloat
|
|
disableVm:
|
|
doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
|
|
when not defined(js):
|
|
doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586
|
|
doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
|
|
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
|
|
doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
|
|
["1,0e-11", "1,0e-011"]
|
|
block: # formatFloat
|
|
disableVm:
|
|
# bug #6589
|
|
when not defined(js):
|
|
doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
|
|
|
|
block: # `%`
|
|
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
|
doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
|
|
doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
|
|
"The cat eats fish."
|
|
|
|
block: # formatSize
|
|
disableVm:
|
|
when not defined(js):
|
|
doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231
|
|
doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
|
|
doAssert formatSize(4096) == "4KiB"
|
|
doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB"
|
|
doAssert formatSize(4096, includeSpace = true) == "4 KiB"
|
|
doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB"
|
|
|
|
block: # formatEng
|
|
disableVm:
|
|
doAssert formatEng(0, 2, trim = false) == "0.00"
|
|
doAssert formatEng(0, 2) == "0"
|
|
doAssert formatEng(53, 2, trim = false) == "53.00"
|
|
doAssert formatEng(0.053, 2, trim = false) == "53.00e-3"
|
|
doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3"
|
|
doAssert formatEng(0.053, 4, trim = true) == "53e-3"
|
|
doAssert formatEng(0.053, 0) == "53e-3"
|
|
doAssert formatEng(52731234) == "52.731234e6"
|
|
doAssert formatEng(-52731234) == "-52.731234e6"
|
|
doAssert formatEng(52731234, 1) == "52.7e6"
|
|
doAssert formatEng(-52731234, 1) == "-52.7e6"
|
|
doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6"
|
|
doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6"
|
|
|
|
doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV"
|
|
doAssert formatEng(4.1, siPrefix = true, unit = "V",
|
|
useUnitSpace = true) == "4.1 V"
|
|
doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space
|
|
doAssert formatEng(4100, siPrefix = true) == "4.1 k"
|
|
doAssert formatEng(4.1, siPrefix = true, unit = "",
|
|
useUnitSpace = true) == "4.1 " # Includes space
|
|
doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k"
|
|
doAssert formatEng(4100) == "4.1e3"
|
|
doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V"
|
|
doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 "
|
|
# Don't use SI prefix as number is too big
|
|
doAssert formatEng(3.1e22, siPrefix = true, unit = "a",
|
|
useUnitSpace = true) == "31e21 a"
|
|
# Don't use SI prefix as number is too small
|
|
doAssert formatEng(3.1e-25, siPrefix = true, unit = "A",
|
|
useUnitSpace = true) == "310e-27 A"
|
|
|
|
block: # align
|
|
doAssert align("abc", 4) == " abc"
|
|
doAssert align("a", 0) == "a"
|
|
doAssert align("1232", 6) == " 1232"
|
|
doAssert align("1232", 6, '#') == "##1232"
|
|
|
|
block: # alignLeft
|
|
doAssert alignLeft("abc", 4) == "abc "
|
|
doAssert alignLeft("a", 0) == "a"
|
|
doAssert alignLeft("1232", 6) == "1232 "
|
|
doAssert alignLeft("1232", 6, '#') == "1232##"
|
|
|
|
block: # center
|
|
doAssert center("foo", 13) == " foo "
|
|
doAssert center("foo", 0) == "foo"
|
|
doAssert center("foo", 3, fillChar = 'a') == "foo"
|
|
doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
|
|
|
|
block: # count
|
|
doAssert count("foofoofoo", "foofoo") == 1
|
|
doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
|
|
doAssert count("foofoofoo", 'f') == 3
|
|
doAssert count("foofoofoobar", {'f', 'b'}) == 4
|
|
|
|
block: # isAlphaAscii
|
|
doAssert isAlphaAscii('r')
|
|
doAssert isAlphaAscii('A')
|
|
doAssert(not isAlphaAscii('$'))
|
|
|
|
block: # isAlphaNumeric
|
|
doAssert isAlphaNumeric('3')
|
|
doAssert isAlphaNumeric('R')
|
|
doAssert(not isAlphaNumeric('!'))
|
|
|
|
block: # isDigit
|
|
doAssert isDigit('3')
|
|
doAssert(not isDigit('a'))
|
|
doAssert(not isDigit('%'))
|
|
|
|
block: # isSpaceAscii
|
|
doAssert isSpaceAscii('\t')
|
|
doAssert isSpaceAscii('\l')
|
|
doAssert(not isSpaceAscii('A'))
|
|
|
|
block: # isEmptyOrWhitespace
|
|
doAssert(isEmptyOrWhitespace(""))
|
|
doAssert(isEmptyOrWhitespace(" "))
|
|
doAssert(isEmptyOrWhitespace("\t\l \v\r\f"))
|
|
doAssert(not isEmptyOrWhitespace("ABc \td"))
|
|
|
|
block: # isLowerAscii
|
|
doAssert isLowerAscii('a')
|
|
doAssert isLowerAscii('z')
|
|
doAssert(not isLowerAscii('A'))
|
|
doAssert(not isLowerAscii('5'))
|
|
doAssert(not isLowerAscii('&'))
|
|
doAssert(not isLowerAscii(' '))
|
|
|
|
block: # isUpperAscii
|
|
doAssert isUpperAscii('A')
|
|
doAssert(not isUpperAscii('b'))
|
|
doAssert(not isUpperAscii('5'))
|
|
doAssert(not isUpperAscii('%'))
|
|
|
|
block: # unescape
|
|
doAssert(unescape(r"\x013", "", "") == "\x013")
|
|
|
|
block: # join
|
|
doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
|
|
doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
|
|
doAssert join([1, 2, 3]) == "123"
|
|
doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
|
|
|
|
block: # startsWith / endsWith
|
|
var s = "abcdef"
|
|
doAssert s.startsWith('a')
|
|
doAssert s.startsWith('b') == false
|
|
doAssert s.endsWith('f')
|
|
doAssert s.endsWith('a') == false
|
|
doAssert s.endsWith('\0') == false
|
|
|
|
block: # nimIdentNormalize
|
|
doAssert nimIdentNormalize("") == ""
|
|
doAssert nimIdentNormalize("foo") == "foo"
|
|
doAssert nimIdentNormalize("foo_bar") == "foobar"
|
|
doAssert nimIdentNormalize("Foo_bar") == "Foobar"
|
|
doAssert nimIdentNormalize("_Foo_bar") == "_foobar"
|
|
|
|
static: main()
|
|
main()
|