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