Skip to content

Commit 2e7f1f5

Browse files
authored
Merge pull request #2489 from advikkabra/isspace-fix
Fix isspace edge case
2 parents b7929f0 + 3210c45 commit 2e7f1f5

File tree

3 files changed

+45
-29
lines changed

3 files changed

+45
-29
lines changed

integration_tests/test_str_attributes.py

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ def lower():
2121
assert "DDd12Vv" .lower() == "ddd12vv"
2222
assert "".lower() == ""
2323

24+
2425
def upper():
2526
s: str
2627
s = "AaaaAABBbbbbBB!@12223BN"
2728
assert s.upper() == "AAAAAABBBBBBBB!@12223BN"
2829
assert "DDd12Vv".upper() == "DDD12VV"
2930
assert "".upper() == ""
3031

32+
3133
def strip():
3234
s: str
3335
s = " AASAsaSas "
@@ -88,14 +90,15 @@ def startswith():
8890
assert s.startswith("sdd") == False
8991
assert "".startswith("ok") == False
9092

93+
9194
def endswith():
9295

9396
# The following test suite fulfils the control flow graph coverage
9497
# in terms of Statement Coverage and Branch Coverage associated with endwith() functionality.
9598

96-
# Case 1: When string is constant and suffix is also constant
99+
# Case 1: When string is constant and suffix is also constant
97100
assert "".endswith("") == True
98-
assert "".endswith(" ") == False
101+
assert "".endswith(" ") == False
99102
assert "".endswith("%") == False
100103
assert "".endswith("a1234PT#$") == False
101104
assert "".endswith("blah blah") == False
@@ -105,13 +108,12 @@ def endswith():
105108
assert " rendezvous 5:30 ".endswith("apple") == False
106109
assert "two plus".endswith("longer than string") == False
107110

108-
109111
# Case 2: When string is constant and suffix is variable
110112
suffix: str
111113
suffix = ""
112114
assert "".endswith(suffix) == True
113115
suffix = " "
114-
assert "".endswith(suffix) == False
116+
assert "".endswith(suffix) == False
115117
suffix = "5:30 "
116118
assert " rendezvous 5:30 ".endswith(suffix) == True
117119
suffix = ""
@@ -138,13 +140,14 @@ def endswith():
138140
suffix = "apple"
139141
assert s.endswith(suffix) == False
140142

143+
141144
def partition():
142-
143-
# Note: Both string or seperator cannot be empty
144-
# Case 1: When string is constant and seperator is also constant
145-
assert " ".partition(" ") == (""," "," ")
146-
assert "apple mango".partition(" ") == ("apple"," ","mango")
147-
assert "applemango".partition("afdnjkfsn") == ("applemango","","")
145+
146+
# Note: Both string or seperator cannot be empty
147+
# Case 1: When string is constant and seperator is also constant
148+
assert " ".partition(" ") == ("", " ", " ")
149+
assert "apple mango".partition(" ") == ("apple", " ", "mango")
150+
assert "applemango".partition("afdnjkfsn") == ("applemango", "", "")
148151
assert "applemango".partition("an") == ("applem", "an", "go")
149152
assert "applemango".partition("mango") == ("apple", "mango", "")
150153
assert "applemango".partition("applemango") == ("", "applemango", "")
@@ -154,15 +157,17 @@ def partition():
154157
# Case 2: When string is constant and seperator is variable
155158
seperator: str
156159
seperator = " "
157-
assert " ".partition(seperator) == (""," "," ")
160+
assert " ".partition(seperator) == ("", " ", " ")
158161
seperator = " "
159-
assert "apple mango".partition(seperator) == ("apple"," ","mango")
162+
assert "apple mango".partition(seperator) == ("apple", " ", "mango")
160163
seperator = "5:30 "
161-
assert " rendezvous 5:30 ".partition(seperator) == (" rendezvous ", "5:30 ", "")
164+
assert " rendezvous 5:30 ".partition(
165+
seperator) == (" rendezvous ", "5:30 ", "")
162166
seperator = "^&"
163167
assert "@#$%^&*()#!".partition(seperator) == ("@#$%", "^&", "*()#!")
164168
seperator = "daddada "
165-
assert " rendezvous 5:30 ".partition(seperator) == (" rendezvous 5:30 ", "", "")
169+
assert " rendezvous 5:30 ".partition(
170+
seperator) == (" rendezvous 5:30 ", "", "")
166171
seperator = "longer than string"
167172
assert "two plus".partition(seperator) == ("two plus", "", "")
168173

@@ -182,6 +187,7 @@ def partition():
182187
seperator = "apple"
183188
assert s.partition(seperator) == ("rendezvous 5", "", "")
184189

190+
185191
def is_lower():
186192
# Case 1: When constant string is present
187193
assert "".islower() == False
@@ -204,8 +210,9 @@ def is_lower():
204210
s = "apple is a fruit"
205211
assert s.islower() == True
206212

213+
207214
def is_upper():
208-
# Case 1: When constant string is present
215+
# Case 1: When constant string is present
209216
assert "".isupper() == False
210217
assert "apple".isupper() == False
211218
assert "4432632479".isupper() == False
@@ -226,6 +233,7 @@ def is_upper():
226233
s = "APPLE IS A FRUIT"
227234
assert s.isupper() == True
228235

236+
229237
def is_decimal():
230238
# Case 1: When constant string is present
231239
assert "".isdecimal() == False
@@ -251,6 +259,7 @@ def is_decimal():
251259
s = "12 34"
252260
assert s.isdecimal() == False
253261

262+
254263
def is_ascii():
255264
# Case 1: When constant string is present
256265
assert "".isascii() == True
@@ -280,12 +289,16 @@ def is_ascii():
280289
def is_space():
281290
assert "\n".isspace() == True
282291
assert " ".isspace() == True
283-
assert "\r".isspace() == True
292+
assert "\r".isspace() == True
293+
assert "".isspace() == False
284294

285-
s:str = " "
286-
assert s.isspace() == True
295+
s: str = " "
296+
assert s.isspace() == True
287297
s = "a"
288298
assert s.isspace() == False
299+
s = ""
300+
assert s.isspace() == False
301+
289302

290303
def check():
291304
capitalize()
@@ -303,4 +316,5 @@ def check():
303316
is_ascii()
304317
is_space()
305318

319+
306320
check()

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7107,18 +7107,18 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
71077107
Return True if all cased characters in the string are uppercase and there is at least one cased character, False otherwise.
71087108
*/
71097109
bool is_cased_present = false;
7110-
bool is_lower = true;
7110+
bool is_upper = true;
71117111
for (auto &i : s_var) {
71127112
if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z')) {
71137113
is_cased_present = true;
71147114
if(!(i >= 'A' && i <= 'Z')) {
7115-
is_lower = false;
7115+
is_upper = false;
71167116
break;
71177117
}
71187118
}
71197119
}
7120-
is_lower = is_lower && is_cased_present;
7121-
tmp = ASR::make_LogicalConstant_t(al, loc, is_lower,
7120+
is_upper = is_upper && is_cased_present;
7121+
tmp = ASR::make_LogicalConstant_t(al, loc, is_upper,
71227122
ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)));
71237123
return;
71247124
} else if(attr_name == "isdecimal") {
@@ -7160,13 +7160,13 @@ characters, as defined by CPython. Return false otherwise. For now we use the
71607160
std::isspace function, but if we later discover that it differs from CPython,
71617161
we will have to use something else.
71627162
*/
7163-
bool is_space = true;
7164-
for (char i : s_var) {
7165-
if (!std::isspace(static_cast<unsigned char>(i))) {
7166-
is_space = false;
7167-
break;
7168-
}
7163+
bool is_space = (s_var.size() != 0);
7164+
for (char i : s_var) {
7165+
if (!std::isspace(static_cast<unsigned char>(i))) {
7166+
is_space = false;
7167+
break;
71697168
}
7169+
}
71707170
tmp = ASR::make_LogicalConstant_t(al, loc, is_space,
71717171
ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)));
71727172
return;

src/runtime/lpython_builtin.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ def _lpython_str_isdecimal(s: str) -> bool:
955955

956956
@overload
957957
def _lpython_str_isascii(s: str) -> bool:
958-
if(len(s) == 0):
958+
if len(s) == 0:
959959
return True
960960
i: str
961961
for i in s:
@@ -964,6 +964,8 @@ def _lpython_str_isascii(s: str) -> bool:
964964
return True
965965

966966
def _lpython_str_isspace(s:str) -> bool:
967+
if len(s) == 0:
968+
return False
967969
ch: str
968970
for ch in s:
969971
if ch != ' ' and ch != '\t' and ch != '\n' and ch != '\r' and ch != '\f' and ch != '\v':

0 commit comments

Comments
 (0)