Skip to content

Commit

Permalink
Merge pull request lcompilers#2489 from advikkabra/isspace-fix
Browse files Browse the repository at this point in the history
Fix isspace edge case
  • Loading branch information
anutosh491 committed Feb 12, 2024
2 parents b7929f0 + 3210c45 commit 2e7f1f5
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 29 deletions.
50 changes: 32 additions & 18 deletions integration_tests/test_str_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ def lower():
assert "DDd12Vv" .lower() == "ddd12vv"
assert "".lower() == ""


def upper():
s: str
s = "AaaaAABBbbbbBB!@12223BN"
assert s.upper() == "AAAAAABBBBBBBB!@12223BN"
assert "DDd12Vv".upper() == "DDD12VV"
assert "".upper() == ""


def strip():
s: str
s = " AASAsaSas "
Expand Down Expand Up @@ -88,14 +90,15 @@ def startswith():
assert s.startswith("sdd") == False
assert "".startswith("ok") == False


def endswith():

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

# Case 1: When string is constant and suffix is also constant
# Case 1: When string is constant and suffix is also constant
assert "".endswith("") == True
assert "".endswith(" ") == False
assert "".endswith(" ") == False
assert "".endswith("%") == False
assert "".endswith("a1234PT#$") == False
assert "".endswith("blah blah") == False
Expand All @@ -105,13 +108,12 @@ def endswith():
assert " rendezvous 5:30 ".endswith("apple") == False
assert "two plus".endswith("longer than string") == False


# Case 2: When string is constant and suffix is variable
suffix: str
suffix = ""
assert "".endswith(suffix) == True
suffix = " "
assert "".endswith(suffix) == False
assert "".endswith(suffix) == False
suffix = "5:30 "
assert " rendezvous 5:30 ".endswith(suffix) == True
suffix = ""
Expand All @@ -138,13 +140,14 @@ def endswith():
suffix = "apple"
assert s.endswith(suffix) == False


def partition():
# Note: Both string or seperator cannot be empty
# Case 1: When string is constant and seperator is also constant
assert " ".partition(" ") == (""," "," ")
assert "apple mango".partition(" ") == ("apple"," ","mango")
assert "applemango".partition("afdnjkfsn") == ("applemango","","")

# Note: Both string or seperator cannot be empty
# Case 1: When string is constant and seperator is also constant
assert " ".partition(" ") == ("", " ", " ")
assert "apple mango".partition(" ") == ("apple", " ", "mango")
assert "applemango".partition("afdnjkfsn") == ("applemango", "", "")
assert "applemango".partition("an") == ("applem", "an", "go")
assert "applemango".partition("mango") == ("apple", "mango", "")
assert "applemango".partition("applemango") == ("", "applemango", "")
Expand All @@ -154,15 +157,17 @@ def partition():
# Case 2: When string is constant and seperator is variable
seperator: str
seperator = " "
assert " ".partition(seperator) == (""," "," ")
assert " ".partition(seperator) == ("", " ", " ")
seperator = " "
assert "apple mango".partition(seperator) == ("apple"," ","mango")
assert "apple mango".partition(seperator) == ("apple", " ", "mango")
seperator = "5:30 "
assert " rendezvous 5:30 ".partition(seperator) == (" rendezvous ", "5:30 ", "")
assert " rendezvous 5:30 ".partition(
seperator) == (" rendezvous ", "5:30 ", "")
seperator = "^&"
assert "@#$%^&*()#!".partition(seperator) == ("@#$%", "^&", "*()#!")
seperator = "daddada "
assert " rendezvous 5:30 ".partition(seperator) == (" rendezvous 5:30 ", "", "")
assert " rendezvous 5:30 ".partition(
seperator) == (" rendezvous 5:30 ", "", "")
seperator = "longer than string"
assert "two plus".partition(seperator) == ("two plus", "", "")

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


def is_lower():
# Case 1: When constant string is present
assert "".islower() == False
Expand All @@ -204,8 +210,9 @@ def is_lower():
s = "apple is a fruit"
assert s.islower() == True


def is_upper():
# Case 1: When constant string is present
# Case 1: When constant string is present
assert "".isupper() == False
assert "apple".isupper() == False
assert "4432632479".isupper() == False
Expand All @@ -226,6 +233,7 @@ def is_upper():
s = "APPLE IS A FRUIT"
assert s.isupper() == True


def is_decimal():
# Case 1: When constant string is present
assert "".isdecimal() == False
Expand All @@ -251,6 +259,7 @@ def is_decimal():
s = "12 34"
assert s.isdecimal() == False


def is_ascii():
# Case 1: When constant string is present
assert "".isascii() == True
Expand Down Expand Up @@ -280,12 +289,16 @@ def is_ascii():
def is_space():
assert "\n".isspace() == True
assert " ".isspace() == True
assert "\r".isspace() == True
assert "\r".isspace() == True
assert "".isspace() == False

s:str = " "
assert s.isspace() == True
s: str = " "
assert s.isspace() == True
s = "a"
assert s.isspace() == False
s = ""
assert s.isspace() == False


def check():
capitalize()
Expand All @@ -303,4 +316,5 @@ def check():
is_ascii()
is_space()


check()
20 changes: 10 additions & 10 deletions src/lpython/semantics/python_ast_to_asr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7107,18 +7107,18 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
Return True if all cased characters in the string are uppercase and there is at least one cased character, False otherwise.
*/
bool is_cased_present = false;
bool is_lower = true;
bool is_upper = true;
for (auto &i : s_var) {
if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z')) {
is_cased_present = true;
if(!(i >= 'A' && i <= 'Z')) {
is_lower = false;
is_upper = false;
break;
}
}
}
is_lower = is_lower && is_cased_present;
tmp = ASR::make_LogicalConstant_t(al, loc, is_lower,
is_upper = is_upper && is_cased_present;
tmp = ASR::make_LogicalConstant_t(al, loc, is_upper,
ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)));
return;
} else if(attr_name == "isdecimal") {
Expand Down Expand Up @@ -7160,13 +7160,13 @@ characters, as defined by CPython. Return false otherwise. For now we use the
std::isspace function, but if we later discover that it differs from CPython,
we will have to use something else.
*/
bool is_space = true;
for (char i : s_var) {
if (!std::isspace(static_cast<unsigned char>(i))) {
is_space = false;
break;
}
bool is_space = (s_var.size() != 0);
for (char i : s_var) {
if (!std::isspace(static_cast<unsigned char>(i))) {
is_space = false;
break;
}
}
tmp = ASR::make_LogicalConstant_t(al, loc, is_space,
ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)));
return;
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/lpython_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,7 @@ def _lpython_str_isdecimal(s: str) -> bool:

@overload
def _lpython_str_isascii(s: str) -> bool:
if(len(s) == 0):
if len(s) == 0:
return True
i: str
for i in s:
Expand All @@ -964,6 +964,8 @@ def _lpython_str_isascii(s: str) -> bool:
return True

def _lpython_str_isspace(s:str) -> bool:
if len(s) == 0:
return False
ch: str
for ch in s:
if ch != ' ' and ch != '\t' and ch != '\n' and ch != '\r' and ch != '\f' and ch != '\v':
Expand Down

0 comments on commit 2e7f1f5

Please sign in to comment.