1# mode: run
2# tag: cpp, warnings
3
4cimport cython
5
6from libcpp.string cimport string, npos, to_string, stoi, stof
7
8b_asdf = b'asdf'
9b_asdg = b'asdg'
10b_s = b's'
11
12
13cdef int compare_to_asdf_ref(string& s) except -999:
14    return s.compare(b"asdf")
15
16def test_coerced_literal_ref():
17    """
18    >>> test_coerced_literal_ref()
19    0
20    """
21    return compare_to_asdf_ref("asdf")
22
23
24cdef int compare_to_asdf_const_ref(const string& s) except -999:
25    return s.compare(b"asdf")
26
27def test_coerced_literal_const_ref():
28    """
29    >>> test_coerced_literal_const_ref()
30    0
31    """
32    return compare_to_asdf_const_ref("asdf")
33
34
35cdef int compare_to_asdf_const(const string s) except -999:
36    return s.compare(b"asdf")
37
38def test_coerced_literal_const():
39    """
40    >>> test_coerced_literal_const()
41    0
42    """
43    return compare_to_asdf_const("asdf")
44
45
46def test_conversion(py_obj):
47    """
48    >>> test_conversion(b_asdf) == b_asdf or test_conversion(b_asdf)
49    True
50    >>> test_conversion(123)  # doctest: +ELLIPSIS
51    Traceback (most recent call last):
52    TypeError: expected ..., int found
53    """
54    cdef string s = py_obj
55    return s
56
57def test_indexing(char *py_str):
58    """
59    >>> test_indexing(b_asdf)
60    ('s', 's')
61    """
62    cdef string s
63    s = string(py_str)
64    return chr(s[1]), chr(s.at(1))
65
66def test_size(char *py_str):
67    """
68    >>> test_size(b_asdf)
69    (4, 4)
70    """
71    cdef string s
72    s = string(py_str)
73    return s.size(), s.length()
74
75def test_compare(char *a, char *b):
76    """
77    >>> test_compare(b_asdf, b_asdf)
78    0
79
80    >>> test_compare(b_asdf, b_asdg) < 0
81    True
82    """
83    cdef string s = string(a)
84    cdef string t = string(b)
85    return s.compare(t)
86
87def test_empty():
88    """
89    >>> test_empty()
90    (True, False)
91    """
92    cdef string a = string(<char *>b"")
93    cdef string b = string(<char *>b"aa")
94    return a.empty(), b.empty()
95
96def test_push_back(char *a):
97    """
98    >>> test_push_back(b_asdf) == b_asdf + b_s
99    True
100    """
101    cdef string s = string(a)
102    s.push_back(<char>ord('s'))
103    return s.c_str()
104
105def test_pop_back(char *a):
106    """
107    >>> test_pop_back(b'abc') == b'ab' or test_pop_back(b'abc')
108    True
109    """
110    cdef string s = string(a)
111    s.pop_back()
112    return s
113
114def test_insert(char *a, char *b, int i):
115    """
116    >>> test_insert('AAAA'.encode('ASCII'), 'BBBB'.encode('ASCII'), 2) == 'AABBBBAA'.encode('ASCII')
117    True
118    """
119    cdef string s = string(a)
120    cdef string t = string(b)
121    cdef string u = s.insert(i, t)
122    return u.c_str()
123
124def test_copy(char *a):
125    """
126    >>> test_copy(b_asdf) == b_asdf[1:]
127    True
128    """
129    cdef string t = string(a)
130    cdef char[6] buffer
131    cdef size_t length = t.copy(buffer, 4, 1)
132    buffer[length] = c'\0'
133    return buffer
134
135def test_find(char *a, char *b):
136    """
137    >>> test_find(b_asdf, 'df'.encode('ASCII'))
138    2
139    """
140    cdef string s = string(a)
141    cdef string t = string(b)
142    cdef size_t i = s.find(t)
143    return i
144
145def test_npos(char *a, char *b):
146    """
147    >>> test_npos(b'abc', b'x')
148    True
149    >>> test_npos(b'abc', b'a')
150    False
151    """
152    cdef string s = string(a)
153    cdef string st = string(b)
154    return s.find(st) == npos
155
156def test_clear():
157    """
158    >>> test_clear() == ''.encode('ASCII')
159    True
160    """
161    cdef string s = string(<char *>"asdf")
162    s.clear()
163    return s.c_str()
164
165def test_erase(char *a, size_t pos=0, size_t count=npos):
166    """
167    >>> test_erase(b'abc') == b'' or test_erase(b'abc')
168    True
169    >>> test_erase(b'abc', 1) == b'a' or test_erase(b'abc', 1)
170    True
171    >>> test_erase(b'abc', 1, 1) == b'ac' or test_erase(b'abc', 1, 1)
172    True
173    """
174    cdef string s = string(a)
175    return s.erase(pos, count)
176
177def test_assign(char *a):
178    """
179    >>> test_assign(b_asdf) == 'ggg'.encode('ASCII')
180    True
181    """
182    cdef string s = string(a)
183    s.assign(<char *>"ggg")
184    return s.c_str()
185
186
187def test_substr(char *a):
188    """
189    >>> test_substr('ABCDEFGH'.encode('ASCII')) == ('BCDEFGH'.encode('ASCII'), 'BCDE'.encode('ASCII'), 'ABCDEFGH'.encode('ASCII'))
190    True
191    """
192    cdef string s = string(a)
193    cdef string x, y, z
194    x = s.substr(1)
195    y = s.substr(1, 4)
196    z = s.substr()
197    return x.c_str(), y.c_str(), z.c_str()
198
199def test_append(char *a, char *b):
200    """
201    >>> test_append(b_asdf, '1234'.encode('ASCII')) == b_asdf + '1234'.encode('ASCII')
202    True
203    """
204    cdef string s = string(a)
205    cdef string t = string(b)
206    cdef string j = s.append(t)
207    return j.c_str()
208
209def test_char_compare(py_str):
210    """
211    >>> test_char_compare(b_asdf)
212    True
213    """
214    cdef char *a = py_str
215    cdef string b = string(a)
216    return b.compare(b) == 0
217
218def test_cstr(char *a):
219    """
220    >>> test_cstr(b_asdf) == b_asdf
221    True
222    """
223    cdef string b = string(a)
224    return b.c_str()
225
226@cython.test_assert_path_exists("//PythonCapiCallNode")
227@cython.test_fail_if_path_exists("//AttributeNode")
228def test_decode(char* a):
229    """
230    >>> print(test_decode(b_asdf))
231    asdf
232    """
233    cdef string b = string(a)
234    return b.decode('ascii')
235
236
237@cython.test_assert_path_exists("//ReturnStatNode//PythonCapiCallNode")
238def test_cstr_decode(char* a):
239    """
240    >>> print(test_cstr_decode(b_asdf))
241    asdf
242    """
243    cdef string b = string(a)
244    return b.c_str().decode('utf-8')
245
246
247@cython.test_assert_path_exists("//ReturnStatNode//PythonCapiCallNode")
248@cython.test_fail_if_path_exists("//ReturnStatNode//AttributeNode")
249def test_cstr_ptr_decode(char* a):
250    """
251    >>> print(test_cstr_ptr_decode(b_asdf))
252    asdf
253    """
254    cdef string b = string(a)
255    s = b.c_str()
256    return s.decode('utf-8')
257
258
259@cython.test_assert_path_exists("//PythonCapiCallNode")
260@cython.test_fail_if_path_exists("//AttributeNode")
261def test_decode_sliced(char* a):
262    """
263    >>> print(test_decode_sliced(b_asdf))
264    sd
265    """
266    cdef string b = string(a)
267    return b[1:3].decode('ascii')
268
269@cython.test_assert_path_exists("//PythonCapiCallNode")
270@cython.test_fail_if_path_exists("//AttributeNode")
271def test_decode_sliced_negative(char* a):
272    """
273    >>> a,b,c,d = test_decode_sliced_negative(b_asdf)
274    >>> print(a)
275    sd
276    >>> print(b)
277    a
278    >>> print(c)
279    <BLANKLINE>
280    >>> print(d)
281    <BLANKLINE>
282    """
283    cdef string b = string(a)
284    return b[-3:-1].decode('ascii'), b[-5:-3].decode('ascii'), b[-20:-4].decode('ascii'), b[-2:-20].decode('ascii')
285
286@cython.test_assert_path_exists("//PythonCapiCallNode")
287@cython.test_fail_if_path_exists("//AttributeNode")
288def test_decode_sliced_end(char* a):
289    """
290    >>> a,b = test_decode_sliced_end(b_asdf)
291    >>> print(a)
292    asd
293    >>> print(b)
294    asdf
295    """
296    cdef string b = string(a)
297    return b[:3].decode('ascii'), b[:42].decode('ascii')
298
299@cython.test_assert_path_exists("//PythonCapiCallNode")
300@cython.test_fail_if_path_exists("//AttributeNode")
301def test_decode_sliced_end_negative(char* a):
302    """
303    >>> a,b,c = test_decode_sliced_end_negative(b_asdf)
304    >>> print(a)
305    asd
306    >>> print(b)
307    a
308    >>> print(c)
309    <BLANKLINE>
310    """
311    cdef string b = string(a)
312    return b[:-1].decode('ascii'), b[:-3].decode('ascii'), b[:-4].decode('ascii')
313
314@cython.test_assert_path_exists("//PythonCapiCallNode")
315@cython.test_fail_if_path_exists("//AttributeNode")
316def test_decode_sliced_start(char* a):
317    """
318    >>> print(test_decode_sliced_start(b_asdf))
319    df
320    """
321    cdef string b = string(a)
322    return b[2:].decode('ascii')
323
324@cython.test_assert_path_exists("//PythonCapiCallNode")
325@cython.test_fail_if_path_exists("//AttributeNode")
326def test_decode_sliced_start_negative(char* a):
327    """
328    >>> a,b = test_decode_sliced_start_negative(b_asdf)
329    >>> print(a)
330    df
331    >>> print(b)
332    asdf
333    """
334    cdef string b = string(a)
335    return b[-2:].decode('ascii'), b[-20:].decode('ascii')
336
337def test_equals_operator(char *a, char *b):
338    """
339    >>> test_equals_operator(b_asdf, b_asdf)
340    (True, False)
341    """
342    cdef string s = string(a)
343    cdef string t = string(b)
344    return t == s, t != <char *>"asdf"
345
346def test_less_than(char *a, char *b):
347    """
348    >>> test_less_than(b_asdf[:-1], b_asdf)
349    (True, True, True)
350
351    >>> test_less_than(b_asdf[:-1], b_asdf[:-1])
352    (False, False, True)
353    """
354    cdef string s = string(a)
355    cdef string t = string(b)
356    return (s < t, s < b, s <= b)
357
358def test_greater_than(char *a, char *b):
359    """
360    >>> test_greater_than(b_asdf[:-1], b_asdf)
361    (False, False, False)
362
363    >>> test_greater_than(b_asdf[:-1], b_asdf[:-1])
364    (False, False, True)
365    """
366    cdef string s = string(a)
367    cdef string t = string(b)
368    return (s > t, s > b, s >= b)
369
370
371def test_iteration(string s):
372    """
373    >>> test_iteration(b'xyz')
374    [120, 121, 122]
375    >>> test_iteration(b'')
376    []
377    """
378    return [c for c in s]
379
380
381def test_to_string(x):
382    """
383    >>> print(test_to_string(5))
384    si=5 sl=5 ss=5 sss=5
385    >>> print(test_to_string(-5))
386    si=-5 sl=-5 ss=5 sss=-5
387    """
388    si = to_string(<int>x).decode('ascii')
389    sl = to_string(<long>x).decode('ascii')
390    ss = to_string(<size_t>abs(x)).decode('ascii')
391    sss = to_string(<ssize_t>x).decode('ascii')
392    return f"si={si} sl={sl} ss={ss} sss={sss}"
393
394
395def test_stoi(char *a):
396    """
397    >>> test_stoi(b'5')
398    5
399    """
400    cdef string s = string(a)
401    return stoi(s)
402
403
404def test_stof(char *a):
405    """
406    >>> test_stof(b'5.5')
407    5.5
408    """
409    cdef string s = string(a)
410    return stof(s)
411
412
413_WARNINGS = """
41421:31: Cannot pass Python object as C++ data structure reference (string &), will pass by copy.
415"""
416