1# Tests of Starlark 'string'
2# option:set
3
4load("assert.star", "assert")
5
6# raw string literals:
7assert.eq(r"a\bc", "a\\bc")
8
9# truth
10assert.true("abc")
11assert.true(chr(0))
12assert.true(not "")
13
14# str + str
15assert.eq("a" + "b" + "c", "abc")
16
17# str * int, int * str
18assert.eq("abc" * 0, "")
19assert.eq("abc" * -1, "")
20assert.eq("abc" * 1, "abc")
21assert.eq("abc" * 5, "abcabcabcabcabc")
22assert.eq(0 * "abc", "")
23assert.eq(-1 * "abc", "")
24assert.eq(1 * "abc", "abc")
25assert.eq(5 * "abc", "abcabcabcabcabc")
26assert.fails(lambda: 1.0 * "abc", "unknown.*float \\* str")
27assert.fails(lambda: "abc" * (1000000 * 1000000), "repeat count 1000000000000 too large")
28assert.fails(lambda: "abc" * 1000000 * 1000000, "excessive repeat \\(3000000 \\* 1000000 elements")
29
30# len
31assert.eq(len("Hello, 世界!"), 14)
32assert.eq(len("𐐷"), 4) # U+10437 has a 4-byte UTF-8 encoding (and a 2-code UTF-16 encoding)
33
34# chr & ord
35assert.eq(chr(65), "A") # 1-byte UTF-8 encoding
36assert.eq(chr(1049), "Й") # 2-byte UTF-8 encoding
37assert.eq(chr(0x1F63F), "😿") # 4-byte UTF-8 encoding
38assert.fails(lambda: chr(-1), "Unicode code point -1 out of range \\(<0\\)")
39assert.fails(lambda: chr(0x110000), "Unicode code point U\\+110000 out of range \\(>0x10FFFF\\)")
40assert.eq(ord("A"), 0x41)
41assert.eq(ord("Й"), 0x419)
42assert.eq(ord("世"), 0x4e16)
43assert.eq(ord("😿"), 0x1F63F)
44assert.eq(ord("Й"[1:]), 0xFFFD) # = Unicode replacement character
45assert.fails(lambda: ord("abc"), "string encodes 3 Unicode code points, want 1")
46assert.fails(lambda: ord(""), "string encodes 0 Unicode code points, want 1")
47assert.fails(lambda: ord("😿"[1:]), "string encodes 3 Unicode code points, want 1") # 3 x 0xFFFD
48
49# string.codepoint_ords
50assert.eq(type("abcЙ😿".codepoint_ords()), "string.codepoints")
51assert.eq(str("abcЙ😿".codepoint_ords()), '"abcЙ😿".codepoint_ords()')
52assert.eq(list("abcЙ😿".codepoint_ords()), [97, 98, 99, 1049, 128575])
53assert.eq(list(("A" + "😿Z"[1:]).codepoint_ords()), [ord("A"), 0xFFFD, 0xFFFD, 0xFFFD, ord("Z")])
54assert.eq(list("".codepoint_ords()), [])
55assert.fails(lambda: "abcЙ😿".codepoint_ords()[2], "unhandled index") # not indexable
56assert.fails(lambda: len("abcЙ😿".codepoint_ords()), "no len") # unknown length
57
58# string.codepoints
59assert.eq(type("abcЙ😿".codepoints()), "string.codepoints")
60assert.eq(str("abcЙ😿".codepoints()), '"abcЙ😿".codepoints()')
61assert.eq(list("abcЙ😿".codepoints()), ["a", "b", "c", "Й", "😿"])
62assert.eq(list(("A" + "😿Z"[1:]).codepoints()), ["A", "�", "�", "�", "Z"])
63assert.eq(list("".codepoints()), [])
64assert.fails(lambda: "abcЙ😿".codepoints()[2], "unhandled index") # not indexable
65assert.fails(lambda: len("abcЙ😿".codepoints()), "no len") # unknown length
66
67# string.elem_ords
68assert.eq(type("abcЙ😿".elem_ords()), "string.elems")
69assert.eq(str("abcЙ😿".elem_ords()), '"abcЙ😿".elem_ords()')
70assert.eq(list("abcЙ😿".elem_ords()), [97, 98, 99, 208, 153, 240, 159, 152, 191])
71assert.eq(list(("A" + "😿Z"[1:]).elem_ords()), [65, 159, 152, 191, 90])
72assert.eq(list("".elem_ords()), [])
73assert.eq("abcЙ😿".elem_ords()[2], 99) # indexable
74assert.eq(len("abcЙ😿".elem_ords()), 9) # known length
75
76# string.elems (1-byte substrings, which are invalid text)
77assert.eq(type("abcЙ😿".elems()), "string.elems")
78assert.eq(str("abcЙ😿".elems()), '"abcЙ😿".elems()')
79assert.eq(
80 repr(list("abcЙ😿".elems())),
81 r'["a", "b", "c", "\xd0", "\x99", "\xf0", "\x9f", "\x98", "\xbf"]',
82)
83assert.eq(
84 repr(list(("A" + "😿Z"[1:]).elems())),
85 r'["A", "\x9f", "\x98", "\xbf", "Z"]',
86)
87assert.eq(list("".elems()), [])
88assert.eq("abcЙ😿".elems()[2], "c") # indexable
89assert.eq(len("abcЙ😿".elems()), 9) # known length
90
91# indexing, x[i]
92assert.eq("Hello, 世界!"[0], "H")
93assert.eq(repr("Hello, 世界!"[7]), r'"\xe4"') # (invalid text)
94assert.eq("Hello, 世界!"[13], "!")
95assert.fails(lambda: "abc"[-4], "out of range")
96assert.eq("abc"[-3], "a")
97assert.eq("abc"[-2], "b")
98assert.eq("abc"[-1], "c")
99assert.eq("abc"[0], "a")
100assert.eq("abc"[1], "b")
101assert.eq("abc"[2], "c")
102assert.fails(lambda: "abc"[4], "out of range")
103
104# x[i] = ...
105def f():
106 "abc"[1] = "B"
107
108assert.fails(f, "string.*does not support.*assignment")
109
110# slicing, x[i:j]
111assert.eq("abc"[:], "abc")
112assert.eq("abc"[-4:], "abc")
113assert.eq("abc"[-3:], "abc")
114assert.eq("abc"[-2:], "bc")
115assert.eq("abc"[-1:], "c")
116assert.eq("abc"[0:], "abc")
117assert.eq("abc"[1:], "bc")
118assert.eq("abc"[2:], "c")
119assert.eq("abc"[3:], "")
120assert.eq("abc"[4:], "")
121assert.eq("abc"[:-4], "")
122assert.eq("abc"[:-3], "")
123assert.eq("abc"[:-2], "a")
124assert.eq("abc"[:-1], "ab")
125assert.eq("abc"[:0], "")
126assert.eq("abc"[:1], "a")
127assert.eq("abc"[:2], "ab")
128assert.eq("abc"[:3], "abc")
129assert.eq("abc"[:4], "abc")
130assert.eq("abc"[1:2], "b")
131assert.eq("abc"[2:1], "")
132assert.eq(repr("😿"[:1]), r'"\xf0"') # (invalid text)
133
134# non-unit strides
135assert.eq("abcd"[0:4:1], "abcd")
136assert.eq("abcd"[::2], "ac")
137assert.eq("abcd"[1::2], "bd")
138assert.eq("abcd"[4:0:-1], "dcb")
139assert.eq("banana"[7::-2], "aaa")
140assert.eq("banana"[6::-2], "aaa")
141assert.eq("banana"[5::-2], "aaa")
142assert.eq("banana"[4::-2], "nnb")
143assert.eq("banana"[::-1], "ananab")
144assert.eq("banana"[None:None:-2], "aaa")
145assert.fails(lambda: "banana"[1.0::], "invalid start index: got float, want int")
146assert.fails(lambda: "banana"[:"":], "invalid end index: got string, want int")
147assert.fails(lambda: "banana"[:"":True], "invalid slice step: got bool, want int")
148
149# in, not in
150assert.true("oo" in "food")
151assert.true("ox" not in "food")
152assert.true("" in "food")
153assert.true("" in "")
154assert.fails(lambda: 1 in "", "requires string as left operand")
155assert.fails(lambda: "" in 1, "unknown binary op: string in int")
156
157# ==, !=
158assert.eq("hello", "he" + "llo")
159assert.ne("hello", "Hello")
160
161# hash must follow java.lang.String.hashCode.
162wanthash = {
163 "": 0,
164 "\0" * 100: 0,
165 "hello": 99162322,
166 "world": 113318802,
167 "Hello, 世界!": 417292677,
168}
169gothash = {s: hash(s) for s in wanthash}
170assert.eq(gothash, wanthash)
171
172# TODO(adonovan): ordered comparisons
173
174# string % tuple formatting
175assert.eq("A %d %x Z" % (123, 456), "A 123 1c8 Z")
176assert.eq("A %(foo)d %(bar)s Z" % {"foo": 123, "bar": "hi"}, "A 123 hi Z")
177assert.eq("%s %r" % ("hi", "hi"), 'hi "hi"') # TODO(adonovan): use ''-quotation
178assert.eq("%%d %d" % 1, "%d 1")
179assert.fails(lambda: "%d %d" % 1, "not enough arguments for format string")
180assert.fails(lambda: "%d %d" % (1, 2, 3), "too many arguments for format string")
181assert.fails(lambda: "" % 1, "too many arguments for format string")
182
183# %c
184assert.eq("%c" % 65, "A")
185assert.eq("%c" % 0x3b1, "α")
186assert.eq("%c" % "A", "A")
187assert.eq("%c" % "α", "α")
188assert.fails(lambda: "%c" % "abc", "requires a single-character string")
189assert.fails(lambda: "%c" % "", "requires a single-character string")
190assert.fails(lambda: "%c" % 65.0, "requires int or single-character string")
191assert.fails(lambda: "%c" % 10000000, "requires a valid Unicode code point")
192assert.fails(lambda: "%c" % -1, "requires a valid Unicode code point")
193# TODO(adonovan): more tests
194
195# str.format
196assert.eq("a{}b".format(123), "a123b")
197assert.eq("a{}b{}c{}d{}".format(1, 2, 3, 4), "a1b2c3d4")
198assert.eq("a{{b".format(), "a{b")
199assert.eq("a}}b".format(), "a}b")
200assert.eq("a{{b}}c".format(), "a{b}c")
201assert.eq("a{x}b{y}c{}".format(1, x = 2, y = 3), "a2b3c1")
202assert.fails(lambda: "a{z}b".format(x = 1), "keyword z not found")
203assert.fails(lambda: "{-1}".format(1), "keyword -1 not found")
204assert.fails(lambda: "{-0}".format(1), "keyword -0 not found")
205assert.fails(lambda: "{+0}".format(1), "keyword \\+0 not found")
206assert.fails(lambda: "{+1}".format(1), "keyword \\+1 not found") # starlark-go/issues/114
207assert.eq("{0000000000001}".format(0, 1), "1")
208assert.eq("{012}".format(*range(100)), "12") # decimal, despite leading zeros
209assert.fails(lambda: "{0,1} and {1}".format(1, 2), "keyword 0,1 not found")
210assert.fails(lambda: "a{123}b".format(), "tuple index out of range")
211assert.fails(lambda: "a{}b{}c".format(1), "tuple index out of range")
212assert.eq("a{010}b".format(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), "a10b") # index is decimal
213assert.fails(lambda: "a{}b{1}c".format(1, 2), "cannot switch from automatic field numbering to manual")
214assert.eq("a{!s}c".format("b"), "abc")
215assert.eq("a{!r}c".format("b"), r'a"b"c')
216assert.eq("a{x!r}c".format(x = "b"), r'a"b"c')
217assert.fails(lambda: "{x!}".format(x = 1), "unknown conversion")
218assert.fails(lambda: "{x!:}".format(x = 1), "unknown conversion")
219assert.fails(lambda: "{a.b}".format(1), "syntax x.y is not supported")
220assert.fails(lambda: "{a[0]}".format(1), "syntax a\\[i\\] is not supported")
221assert.fails(lambda: "{ {} }".format(1), "nested replacement fields not supported")
222assert.fails(lambda: "{{}".format(1), "single '}' in format")
223assert.fails(lambda: "{}}".format(1), "single '}' in format")
224assert.fails(lambda: "}}{".format(1), "unmatched '{' in format")
225assert.fails(lambda: "}{{".format(1), "single '}' in format")
226
227# str.split, str.rsplit
228assert.eq("a.b.c.d".split("."), ["a", "b", "c", "d"])
229assert.eq("a.b.c.d".rsplit("."), ["a", "b", "c", "d"])
230assert.eq("a.b.c.d".split(".", -1), ["a", "b", "c", "d"])
231assert.eq("a.b.c.d".rsplit(".", -1), ["a", "b", "c", "d"])
232assert.eq("a.b.c.d".split(".", 0), ["a.b.c.d"])
233assert.eq("a.b.c.d".rsplit(".", 0), ["a.b.c.d"])
234assert.eq("a.b.c.d".split(".", 1), ["a", "b.c.d"])
235assert.eq("a.b.c.d".rsplit(".", 1), ["a.b.c", "d"])
236assert.eq("a.b.c.d".split(".", 2), ["a", "b", "c.d"])
237assert.eq("a.b.c.d".rsplit(".", 2), ["a.b", "c", "d"])
238assert.eq(" ".split("."), [" "])
239assert.eq(" ".rsplit("."), [" "])
240
241# {,r}split on white space:
242assert.eq(" a bc\n def \t ghi".split(), ["a", "bc", "def", "ghi"])
243assert.eq(" a bc\n def \t ghi".split(None), ["a", "bc", "def", "ghi"])
244assert.eq(" a bc\n def \t ghi".split(None, 0), ["a bc\n def \t ghi"])
245assert.eq(" a bc\n def \t ghi".rsplit(None, 0), [" a bc\n def \t ghi"])
246assert.eq(" a bc\n def \t ghi".split(None, 1), ["a", "bc\n def \t ghi"])
247assert.eq(" a bc\n def \t ghi".rsplit(None, 1), [" a bc\n def", "ghi"])
248assert.eq(" a bc\n def \t ghi".split(None, 2), ["a", "bc", "def \t ghi"])
249assert.eq(" a bc\n def \t ghi".rsplit(None, 2), [" a bc", "def", "ghi"])
250assert.eq(" a bc\n def \t ghi".split(None, 3), ["a", "bc", "def", "ghi"])
251assert.eq(" a bc\n def \t ghi".rsplit(None, 3), [" a", "bc", "def", "ghi"])
252assert.eq(" a bc\n def \t ghi".split(None, 4), ["a", "bc", "def", "ghi"])
253assert.eq(" a bc\n def \t ghi".rsplit(None, 4), ["a", "bc", "def", "ghi"])
254assert.eq(" a bc\n def \t ghi".rsplit(None, 5), ["a", "bc", "def", "ghi"])
255
256assert.eq(" a bc\n def \t ghi ".split(None, 0), ["a bc\n def \t ghi "])
257assert.eq(" a bc\n def \t ghi ".rsplit(None, 0), [" a bc\n def \t ghi"])
258assert.eq(" a bc\n def \t ghi ".split(None, 1), ["a", "bc\n def \t ghi "])
259assert.eq(" a bc\n def \t ghi ".rsplit(None, 1), [" a bc\n def", "ghi"])
260
261# Observe the algorithmic difference when splitting on spaces versus other delimiters.
262assert.eq("--aa--bb--cc--".split("-", 0), ["--aa--bb--cc--"]) # contrast this
263assert.eq(" aa bb cc ".split(None, 0), ["aa bb cc "]) # with this
264assert.eq("--aa--bb--cc--".rsplit("-", 0), ["--aa--bb--cc--"]) # ditto this
265assert.eq(" aa bb cc ".rsplit(None, 0), [" aa bb cc"]) # and this
266
267#
268assert.eq("--aa--bb--cc--".split("-", 1), ["", "-aa--bb--cc--"])
269assert.eq("--aa--bb--cc--".rsplit("-", 1), ["--aa--bb--cc-", ""])
270assert.eq(" aa bb cc ".split(None, 1), ["aa", "bb cc "])
271assert.eq(" aa bb cc ".rsplit(None, 1), [" aa bb", "cc"])
272
273#
274assert.eq("--aa--bb--cc--".split("-", -1), ["", "", "aa", "", "bb", "", "cc", "", ""])
275assert.eq("--aa--bb--cc--".rsplit("-", -1), ["", "", "aa", "", "bb", "", "cc", "", ""])
276assert.eq(" aa bb cc ".split(None, -1), ["aa", "bb", "cc"])
277assert.eq(" aa bb cc ".rsplit(None, -1), ["aa", "bb", "cc"])
278assert.eq(" ".split(None), [])
279assert.eq(" ".rsplit(None), [])
280
281assert.eq("localhost:80".rsplit(":", 1)[-1], "80")
282
283# str.splitlines
284assert.eq("\nabc\ndef".splitlines(), ["", "abc", "def"])
285assert.eq("\nabc\ndef".splitlines(True), ["\n", "abc\n", "def"])
286assert.eq("\nabc\ndef\n".splitlines(), ["", "abc", "def"])
287assert.eq("\nabc\ndef\n".splitlines(True), ["\n", "abc\n", "def\n"])
288assert.eq("".splitlines(), []) #
289assert.eq("".splitlines(True), []) #
290assert.eq("a".splitlines(), ["a"])
291assert.eq("a".splitlines(True), ["a"])
292assert.eq("\n".splitlines(), [""])
293assert.eq("\n".splitlines(True), ["\n"])
294assert.eq("a\n".splitlines(), ["a"])
295assert.eq("a\n".splitlines(True), ["a\n"])
296assert.eq("a\n\nb".splitlines(), ["a", "", "b"])
297assert.eq("a\n\nb".splitlines(True), ["a\n", "\n", "b"])
298assert.eq("a\nb\nc".splitlines(), ["a", "b", "c"])
299assert.eq("a\nb\nc".splitlines(True), ["a\n", "b\n", "c"])
300assert.eq("a\nb\nc\n".splitlines(), ["a", "b", "c"])
301assert.eq("a\nb\nc\n".splitlines(True), ["a\n", "b\n", "c\n"])
302
303# str.{,l,r}strip
304assert.eq(" \tfoo\n ".strip(), "foo")
305assert.eq(" \tfoo\n ".lstrip(), "foo\n ")
306assert.eq(" \tfoo\n ".rstrip(), " \tfoo")
307assert.eq(" \tfoo\n ".strip(""), "foo")
308assert.eq(" \tfoo\n ".lstrip(""), "foo\n ")
309assert.eq(" \tfoo\n ".rstrip(""), " \tfoo")
310assert.eq("blah.h".strip("b.h"), "la")
311assert.eq("blah.h".lstrip("b.h"), "lah.h")
312assert.eq("blah.h".rstrip("b.h"), "bla")
313
314# str.count
315assert.eq("banana".count("a"), 3)
316assert.eq("banana".count("a", 2), 2)
317assert.eq("banana".count("a", -4, -2), 1)
318assert.eq("banana".count("a", 1, 4), 2)
319assert.eq("banana".count("a", 0, -100), 0)
320
321# str.{starts,ends}with
322assert.true("foo".endswith("oo"))
323assert.true(not "foo".endswith("x"))
324assert.true("foo".startswith("fo"))
325assert.true(not "foo".startswith("x"))
326assert.fails(lambda: "foo".startswith(1), "got int.*want string")
327
328#
329assert.true("abc".startswith(("a", "A")))
330assert.true("ABC".startswith(("a", "A")))
331assert.true(not "ABC".startswith(("b", "B")))
332assert.fails(lambda: "123".startswith((1, 2)), "got int, for element 0")
333assert.fails(lambda: "123".startswith(["3"]), "got list")
334
335#
336assert.true("abc".endswith(("c", "C")))
337assert.true("ABC".endswith(("c", "C")))
338assert.true(not "ABC".endswith(("b", "B")))
339assert.fails(lambda: "123".endswith((1, 2)), "got int, for element 0")
340assert.fails(lambda: "123".endswith(["3"]), "got list")
341
342# start/end
343assert.true("abc".startswith("bc", 1))
344assert.true(not "abc".startswith("b", 999))
345assert.true("abc".endswith("ab", None, -1))
346assert.true(not "abc".endswith("b", None, -999))
347
348# str.replace
349assert.eq("banana".replace("a", "o", 1), "bonana")
350assert.eq("banana".replace("a", "o"), "bonono")
351# TODO(adonovan): more tests
352
353# str.{,r}find
354assert.eq("foofoo".find("oo"), 1)
355assert.eq("foofoo".find("ox"), -1)
356assert.eq("foofoo".find("oo", 2), 4)
357assert.eq("foofoo".rfind("oo"), 4)
358assert.eq("foofoo".rfind("ox"), -1)
359assert.eq("foofoo".rfind("oo", 1, 4), 1)
360assert.eq("foofoo".find(""), 0)
361assert.eq("foofoo".rfind(""), 6)
362
363# str.{,r}partition
364assert.eq("foo/bar/wiz".partition("/"), ("foo", "/", "bar/wiz"))
365assert.eq("foo/bar/wiz".rpartition("/"), ("foo/bar", "/", "wiz"))
366assert.eq("foo/bar/wiz".partition("."), ("foo/bar/wiz", "", ""))
367assert.eq("foo/bar/wiz".rpartition("."), ("", "", "foo/bar/wiz"))
368assert.fails(lambda: "foo/bar/wiz".partition(""), "empty separator")
369assert.fails(lambda: "foo/bar/wiz".rpartition(""), "empty separator")
370
371assert.eq("?".join(["foo", "a/b/c.go".rpartition("/")[0]]), "foo?a/b")
372
373# str.is{alpha,...}
374def test_predicates():
375 predicates = ["alnum", "alpha", "digit", "lower", "space", "title", "upper"]
376 table = {
377 "Hello, World!": "title",
378 "hello, world!": "lower",
379 "base64": "alnum lower",
380 "HAL-9000": "upper",
381 "Catch-22": "title",
382 "": "",
383 "\n\t\r": "space",
384 "abc": "alnum alpha lower",
385 "ABC": "alnum alpha upper",
386 "123": "alnum digit",
387 "DŽLJ": "alnum alpha upper",
388 "DžLj": "alnum alpha",
389 "Dž Lj": "title",
390 "džlj": "alnum alpha lower",
391 }
392 for str, want in table.items():
393 got = " ".join([name for name in predicates if getattr(str, "is" + name)()])
394 if got != want:
395 assert.fail("%r matched [%s], want [%s]" % (str, got, want))
396
397test_predicates()
398
399# Strings are not iterable.
400# ok
401assert.eq(len("abc"), 3) # len
402assert.true("a" in "abc") # str in str
403assert.eq("abc"[1], "b") # indexing
404
405# not ok
406def for_string():
407 for x in "abc":
408 pass
409
410def args(*args):
411 return args
412
413assert.fails(lambda: args(*"abc"), "must be iterable, not string") # varargs
414assert.fails(lambda: list("abc"), "got string, want iterable") # list(str)
415assert.fails(lambda: tuple("abc"), "got string, want iterable") # tuple(str)
416assert.fails(lambda: set("abc"), "got string, want iterable") # set(str)
417assert.fails(lambda: set() | "abc", "unknown binary op: set | string") # set union
418assert.fails(lambda: enumerate("ab"), "got string, want iterable") # enumerate
419assert.fails(lambda: sorted("abc"), "got string, want iterable") # sorted
420assert.fails(lambda: [].extend("bc"), "got string, want iterable") # list.extend
421assert.fails(lambda: ",".join("abc"), "got string, want iterable") # string.join
422assert.fails(lambda: dict(["ab"]), "not iterable .*string") # dict
423assert.fails(for_string, "string value is not iterable") # for loop
424assert.fails(lambda: [x for x in "abc"], "string value is not iterable") # comprehension
425assert.fails(lambda: all("abc"), "got string, want iterable") # all
426assert.fails(lambda: any("abc"), "got string, want iterable") # any
427assert.fails(lambda: reversed("abc"), "got string, want iterable") # reversed
428assert.fails(lambda: zip("ab", "cd"), "not iterable: string") # zip
429
430# str.join
431assert.eq(",".join([]), "")
432assert.eq(",".join(["a"]), "a")
433assert.eq(",".join(["a", "b"]), "a,b")
434assert.eq(",".join(["a", "b", "c"]), "a,b,c")
435assert.eq(",".join(("a", "b", "c")), "a,b,c")
436assert.eq("".join(("a", "b", "c")), "abc")
437assert.fails(lambda: "".join(None), "got NoneType, want iterable")
438assert.fails(lambda: "".join(["one", 2]), "join: in list, want string, got int")
439
440# TODO(adonovan): tests for: {,r}index
441
442# str.capitalize
443assert.eq("hElLo, WoRlD!".capitalize(), "Hello, world!")
444assert.eq("por qué".capitalize(), "Por qué")
445assert.eq("¿Por qué?".capitalize(), "¿por qué?")
446
447# str.lower
448assert.eq("hElLo, WoRlD!".lower(), "hello, world!")
449assert.eq("por qué".lower(), "por qué")
450assert.eq("¿Por qué?".lower(), "¿por qué?")
451assert.eq("LJUBOVIĆ".lower(), "ljubović")
452assert.true("dženan ljubović".islower())
453
454# str.upper
455assert.eq("hElLo, WoRlD!".upper(), "HELLO, WORLD!")
456assert.eq("por qué".upper(), "POR QUÉ")
457assert.eq("¿Por qué?".upper(), "¿POR QUÉ?")
458assert.eq("ljubović".upper(), "LJUBOVIĆ")
459assert.true("DŽENAN LJUBOVIĆ".isupper())
460
461# str.title
462assert.eq("hElLo, WoRlD!".title(), "Hello, World!")
463assert.eq("por qué".title(), "Por Qué")
464assert.eq("¿Por qué?".title(), "¿Por Qué?")
465assert.eq("ljubović".title(), "Ljubović")
466assert.true("Dženan Ljubović".istitle())
467assert.true(not "DŽenan LJubović".istitle())
468
469# method spell check
470assert.fails(lambda: "".starts_with, "no .starts_with field.*did you mean .startswith")
471assert.fails(lambda: "".StartsWith, "no .StartsWith field.*did you mean .startswith")
472assert.fails(lambda: "".fin, "no .fin field.*.did you mean .find")
473
474
475# removesuffix
476assert.eq("Apricot".removesuffix("cot"), "Apri")
477assert.eq("Apricot".removesuffix("Cot"), "Apricot")
478assert.eq("Apricot".removesuffix("t"), "Aprico")
479assert.eq("a".removesuffix(""), "a")
480assert.eq("".removesuffix(""), "")
481assert.eq("".removesuffix("a"), "")
482assert.eq("Apricot".removesuffix("co"), "Apricot")
483assert.eq("Apricotcot".removesuffix("cot"), "Apricot")
484
485# removeprefix
486assert.eq("Apricot".removeprefix("Apr"), "icot")
487assert.eq("Apricot".removeprefix("apr"), "Apricot")
488assert.eq("Apricot".removeprefix("A"), "pricot")
489assert.eq("a".removeprefix(""), "a")
490assert.eq("".removeprefix(""), "")
491assert.eq("".removeprefix("a"), "")
492assert.eq("Apricot".removeprefix("pr"), "Apricot")
493assert.eq("AprApricot".removeprefix("Apr"), "Apricot")
View as plain text