Skip to content

Commit

Permalink
Added tests for AnsiStr and fixed issues
Browse files Browse the repository at this point in the history
  • Loading branch information
James Smith authored and James Smith committed Nov 17, 2024
1 parent 397c829 commit f5b9b30
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 10 deletions.
36 changes: 28 additions & 8 deletions src/ansi_string/ansi_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,7 @@ def removesuffix(self, suffix:str, inplace:bool=False) -> 'AnsiString':
else:
return self.clip(end=-len(suffix), inplace=inplace)

def replace(self, old:str, new:Union[str,'AnsiString'], count:int=-1, inplace:bool=False) -> 'AnsiString':
def replace(self, old:str, new:Union[str,'AnsiString','AnsiStr'], count:int=-1, inplace:bool=False) -> 'AnsiString':
'''
Does a find-and-replace - if new is a str, the string the is applied will take on the format settings of the
first character of the old string in each replaced item.
Expand All @@ -1182,7 +1182,9 @@ def replace(self, old:str, new:Union[str,'AnsiString'], count:int=-1, inplace:bo
obj = self
idx = obj.data.find(old)
while (count < 0 or count > 0) and idx >= 0:
if isinstance(new, str):
if isinstance(new, AnsiStr):
replace = AnsiString(new)
elif isinstance(new, str):
replace = AnsiString(new, obj.ansi_settings_at(idx))
else:
replace = new
Expand Down Expand Up @@ -1674,7 +1676,6 @@ def __next__(self) -> 'AnsiString':
class AnsiStr(str):
'''
Immutable version of AnsiString. The advantage of this object is that isinstance(AnsiStr(), str) returns True.
This is currently experimental and not completely tested.
'''
def __new__(
cls,
Expand Down Expand Up @@ -1756,6 +1757,10 @@ def __getitem__(self, val:Union[int, slice]) -> 'AnsiStr':
'''
return AnsiStr(self._ansi_string.__getitem__(val))

def simplify(self):
'''Attempts to simplify formatting by re-parsing the ANSI formatting data'''
return AnsiStr(self.__str__())

def apply_formatting(
self,
settings:Union[AnsiFormat, AnsiSetting, str, int, list, tuple],
Expand Down Expand Up @@ -1859,6 +1864,23 @@ def __iter__(self) -> 'AnsiStr':
''' Iterates over each character of this AnsiStr '''
return iter(_GraphicStrCharIterator(self))

def capitalize(self) -> 'AnsiString':
'''
Return a capitalized version of the string.
More specifically, make the first character have upper case and the rest lower case.
'''
cpy = self._ansi_string.copy()
cpy.capitalize(inplace=True)
return AnsiStr(cpy)

def casefold(self) -> 'AnsiString':
'''
Return a version of the string suitable for caseless comparisons.
'''
cpy = self._ansi_string.copy()
cpy.casefold(inplace=True)
return AnsiStr(cpy)

def center(self, width:int, fillchar:str=' ') -> 'AnsiStr':
'''
Center justification.
Expand All @@ -1883,7 +1905,7 @@ def ljust(self, width:int, fillchar:str=' ') -> 'AnsiStr':
cpy.ljust(width, fillchar, inplace=True)
return AnsiStr(cpy)

def rjust(self, width:int, fillchar:str=' ', inplace:bool=False) -> 'AnsiStr':
def rjust(self, width:int, fillchar:str=' ') -> 'AnsiStr':
'''
Right justification.
Parameters:
Expand Down Expand Up @@ -2079,15 +2101,13 @@ def endswith(self, suffix:str, start:int=None, end:int=None) -> bool:
'''
return self._ansi_string.endswith(suffix, start, end)

def expandtabs(self, tabsize:int=8, inplace:bool=False) -> 'AnsiStr':
def expandtabs(self, tabsize:int=8) -> 'AnsiStr':
'''
Replaces all tab characters with the given number of spaces
Parameters:
tabsize - number of spaces to replace each tab with
inplace - when True, do the conversion in-place and return self;
when False, do the conversion on a copy and return the copy
'''
return self.replace('\t', ' ' * tabsize, inplace=inplace)
return self.replace('\t', ' ' * tabsize)

def find(self, sub:str, start:int=None, end:int=None) -> int:
'''
Expand Down
20 changes: 18 additions & 2 deletions tests/test_ansi_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

if os.path.isdir(SOURCE_DIR):
sys.path.insert(0, SOURCE_DIR)
from ansi_string import en_tty_ansi, AnsiFormat, AnsiString, ColorComponentType, ColourComponentType
from ansi_string import en_tty_ansi, AnsiFormat, AnsiStr, AnsiString, ColorComponentType, ColourComponentType

def _is_windows():
return sys.platform.lower().startswith('win')
Expand All @@ -27,7 +27,7 @@ def __init__(self, loaded_str):
loaded_str = loaded_str.encode()
self.buffer = BytesIO(loaded_str)

class CliTests(unittest.TestCase):
class AnsiStringTests(unittest.TestCase):

@classmethod
def setUpClass(cls):
Expand Down Expand Up @@ -129,6 +129,13 @@ def test_add(self):
'\x1b[1mbold\x1b[0;31mred\x1b[m'
)

def test_add_ansistr(self):
s = AnsiString('bold', 'bold') + AnsiStr('red', 'red')
self.assertEqual(
str(s),
'\x1b[1mbold\x1b[0;31mred\x1b[m'
)

def test_iadd(self):
s = AnsiString('part bold')
s.apply_formatting(AnsiFormat.BOLD, 0, 3)
Expand All @@ -138,6 +145,15 @@ def test_iadd(self):
'\x1b[1mpar\x1b[mt bold\x1b[31mred\x1b[m'
)

def test_iadd_ansistr(self):
s = AnsiString('part bold')
s.apply_formatting(AnsiFormat.BOLD, 0, 3)
s += AnsiStr('red', 'red')
self.assertEqual(
str(s),
'\x1b[1mpar\x1b[mt bold\x1b[31mred\x1b[m'
)

def test_eq(self):
s=AnsiString('red', 'red')
self.assertEqual(s, AnsiString('red', AnsiFormat.FG_RED))
Expand Down

0 comments on commit f5b9b30

Please sign in to comment.