2023-07-27 09:35:24 +02:00
|
|
|
import contextlib
|
|
|
|
import io
|
2024-04-16 16:50:10 +02:00
|
|
|
import tempfile
|
2023-05-30 09:06:49 +02:00
|
|
|
import unittest
|
|
|
|
|
2023-07-27 09:35:24 +02:00
|
|
|
import osc.conf
|
2023-05-30 09:06:49 +02:00
|
|
|
from osc.output import KeyValueTable
|
2024-03-05 15:40:37 +01:00
|
|
|
from osc.output import print_msg
|
2024-04-16 16:50:10 +02:00
|
|
|
from osc.output import safe_write
|
2024-03-07 11:59:51 +01:00
|
|
|
from osc.output import sanitize_text
|
2024-03-05 15:58:43 +01:00
|
|
|
from osc.output import tty
|
2023-05-30 09:06:49 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TestKeyValueTable(unittest.TestCase):
|
|
|
|
def test_empty(self):
|
|
|
|
t = KeyValueTable()
|
|
|
|
self.assertEqual(str(t), "")
|
|
|
|
|
|
|
|
def test_simple(self):
|
|
|
|
t = KeyValueTable()
|
|
|
|
t.add("Key", "Value")
|
|
|
|
t.add("FooBar", "Text")
|
|
|
|
|
|
|
|
expected = """
|
|
|
|
Key : Value
|
|
|
|
FooBar : Text
|
|
|
|
""".strip()
|
|
|
|
self.assertEqual(str(t), expected)
|
|
|
|
|
|
|
|
def test_newline(self):
|
|
|
|
t = KeyValueTable()
|
|
|
|
t.add("Key", "Value")
|
|
|
|
t.newline()
|
|
|
|
t.add("FooBar", "Text")
|
|
|
|
|
|
|
|
expected = """
|
|
|
|
Key : Value
|
|
|
|
|
|
|
|
FooBar : Text
|
|
|
|
""".strip()
|
|
|
|
self.assertEqual(str(t), expected)
|
|
|
|
|
|
|
|
def test_continuation(self):
|
|
|
|
t = KeyValueTable()
|
|
|
|
t.add("Key", ["Value1", "Value2"])
|
|
|
|
|
|
|
|
expected = """
|
|
|
|
Key : Value1
|
|
|
|
Value2
|
|
|
|
""".strip()
|
|
|
|
self.assertEqual(str(t), expected)
|
|
|
|
|
|
|
|
def test_section(self):
|
|
|
|
t = KeyValueTable()
|
|
|
|
t.add("Section", None)
|
|
|
|
t.add("Key", "Value", indent=4)
|
|
|
|
t.add("FooBar", "Text", indent=4)
|
|
|
|
|
|
|
|
expected = """
|
|
|
|
Section
|
|
|
|
Key : Value
|
|
|
|
FooBar : Text
|
|
|
|
""".strip()
|
|
|
|
self.assertEqual(str(t), expected)
|
|
|
|
|
|
|
|
def test_wide_chars(self):
|
|
|
|
t = KeyValueTable()
|
|
|
|
t.add("Key", "Value")
|
|
|
|
t.add("🚀🚀🚀", "Value")
|
|
|
|
|
|
|
|
expected = """
|
|
|
|
Key : Value
|
|
|
|
🚀🚀🚀 : Value
|
|
|
|
""".strip()
|
|
|
|
self.assertEqual(str(t), expected)
|
|
|
|
|
|
|
|
|
2023-07-27 09:35:24 +02:00
|
|
|
class TestPrintMsg(unittest.TestCase):
|
|
|
|
def setUp(self):
|
2024-01-03 21:21:40 +01:00
|
|
|
osc.conf.config = osc.conf.Options()
|
2023-07-27 09:35:24 +02:00
|
|
|
|
|
|
|
def test_debug(self):
|
2023-08-22 15:34:45 +02:00
|
|
|
osc.conf.config["debug"] = False
|
2023-07-27 09:35:24 +02:00
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="debug")
|
|
|
|
self.assertEqual("", stdout.getvalue())
|
|
|
|
self.assertEqual("", stderr.getvalue())
|
|
|
|
|
2023-08-22 15:34:45 +02:00
|
|
|
osc.conf.config["debug"] = True
|
2023-07-27 09:35:24 +02:00
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="debug")
|
|
|
|
self.assertEqual("", stdout.getvalue())
|
|
|
|
self.assertEqual("DEBUG: foo bar\n", stderr.getvalue())
|
|
|
|
|
|
|
|
def test_verbose(self):
|
2023-08-22 15:34:45 +02:00
|
|
|
osc.conf.config["verbose"] = False
|
2023-07-27 09:35:24 +02:00
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="verbose")
|
|
|
|
self.assertEqual("", stdout.getvalue())
|
|
|
|
self.assertEqual("", stderr.getvalue())
|
|
|
|
|
2023-08-22 15:34:45 +02:00
|
|
|
osc.conf.config["verbose"] = True
|
2023-07-27 09:35:24 +02:00
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="verbose")
|
|
|
|
self.assertEqual("foo bar\n", stdout.getvalue())
|
|
|
|
self.assertEqual("", stderr.getvalue())
|
|
|
|
|
2023-08-22 15:34:45 +02:00
|
|
|
osc.conf.config["verbose"] = False
|
|
|
|
osc.conf.config["debug"] = True
|
2023-07-27 09:35:24 +02:00
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="verbose")
|
|
|
|
self.assertEqual("foo bar\n", stdout.getvalue())
|
|
|
|
self.assertEqual("", stderr.getvalue())
|
|
|
|
|
2024-03-05 15:58:43 +01:00
|
|
|
def test_error(self):
|
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="error")
|
|
|
|
self.assertEqual("", stdout.getvalue())
|
|
|
|
self.assertEqual(f"{tty.colorize('ERROR:', 'red,bold')} foo bar\n", stderr.getvalue())
|
|
|
|
|
|
|
|
def test_warning(self):
|
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="warning")
|
|
|
|
self.assertEqual("", stdout.getvalue())
|
|
|
|
self.assertEqual(f"{tty.colorize('WARNING:', 'yellow,bold')} foo bar\n", stderr.getvalue())
|
|
|
|
|
2023-07-27 09:35:24 +02:00
|
|
|
def test_none(self):
|
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to=None)
|
|
|
|
self.assertEqual("", stdout.getvalue())
|
|
|
|
self.assertEqual("", stderr.getvalue())
|
|
|
|
|
|
|
|
def test_stdout(self):
|
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="stdout")
|
|
|
|
self.assertEqual("foo bar\n", stdout.getvalue())
|
|
|
|
self.assertEqual("", stderr.getvalue())
|
|
|
|
|
2024-03-05 15:58:43 +01:00
|
|
|
def test_stderr(self):
|
|
|
|
stdout = io.StringIO()
|
|
|
|
stderr = io.StringIO()
|
|
|
|
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
|
|
print_msg("foo", "bar", print_to="stderr")
|
|
|
|
self.assertEqual("", stdout.getvalue())
|
|
|
|
self.assertEqual("foo bar\n", stderr.getvalue())
|
|
|
|
|
2023-07-27 09:35:24 +02:00
|
|
|
|
2024-03-07 11:59:51 +01:00
|
|
|
class TestSanitization(unittest.TestCase):
|
|
|
|
def test_control_chars_bytes(self):
|
|
|
|
original = b"".join([i.to_bytes(1, byteorder="big") for i in range(32)])
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, b"\t\n\r")
|
|
|
|
|
|
|
|
def test_control_chars_str(self):
|
|
|
|
original = "".join([chr(i) for i in range(32)])
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, "\t\n\r")
|
|
|
|
|
|
|
|
def test_csi_escape_sequences_str(self):
|
|
|
|
# allowed CSI escape sequences
|
|
|
|
originals = [">\033[0m<", ">\033[1;31;47m]<"]
|
|
|
|
for original in originals:
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, original)
|
|
|
|
|
|
|
|
# not allowed CSI escape sequences
|
|
|
|
originals = [">\033[8m<"]
|
|
|
|
for original in originals:
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, "><")
|
|
|
|
|
|
|
|
def test_csi_escape_sequences_bytes(self):
|
|
|
|
# allowed CSI escape sequences
|
|
|
|
originals = [b">\033[0m<", b">\033[1;31;47m]<"]
|
|
|
|
for original in originals:
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, original)
|
|
|
|
|
|
|
|
# not allowed CSI escape sequences
|
|
|
|
originals = [b">\033[8m<"]
|
|
|
|
for original in originals:
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, b"><")
|
|
|
|
|
|
|
|
def test_standalone_escape_str(self):
|
|
|
|
original = ">\033<"
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, "><")
|
|
|
|
|
|
|
|
def test_standalone_escape_bytes(self):
|
|
|
|
# standalone escape
|
|
|
|
original = b">\033<"
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, b"><")
|
|
|
|
|
|
|
|
def test_fe_escape_sequences_str(self):
|
|
|
|
for i in range(0x40, 0x5F + 1):
|
|
|
|
char = chr(i)
|
|
|
|
original = f">\033{char}<"
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, "><")
|
|
|
|
|
|
|
|
def test_fe_escape_sequences_bytes(self):
|
|
|
|
for i in range(0x40, 0x5F + 1):
|
|
|
|
byte = i.to_bytes(1, byteorder="big")
|
|
|
|
original = b">\033" + byte + b"<"
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
self.assertEqual(sanitized, b"><")
|
|
|
|
|
|
|
|
def test_osc_escape_sequences_str(self):
|
|
|
|
# OSC (Operating System Command) sequences
|
|
|
|
original = "\033]0;this is the window title\007"
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
# \033] is removed with the Fe sequences
|
|
|
|
self.assertEqual(sanitized, "0;this is the window title")
|
|
|
|
|
|
|
|
def test_osc_escape_sequences_bytes(self):
|
|
|
|
# OSC (Operating System Command) sequences
|
|
|
|
original = b"\033]0;this is the window title\007"
|
|
|
|
sanitized = sanitize_text(original)
|
|
|
|
# \033] is removed with the Fe sequences
|
|
|
|
self.assertEqual(sanitized, b"0;this is the window title")
|
|
|
|
|
|
|
|
|
2024-04-16 16:50:10 +02:00
|
|
|
class TestSafeWrite(unittest.TestCase):
|
|
|
|
def test_string_to_file(self):
|
|
|
|
with tempfile.NamedTemporaryFile(mode="w+") as f:
|
|
|
|
safe_write(f, "string")
|
|
|
|
|
|
|
|
def test_bytes_to_file(self):
|
|
|
|
with tempfile.NamedTemporaryFile(mode="wb+") as f:
|
|
|
|
safe_write(f, b"bytes")
|
|
|
|
|
|
|
|
def test_string_to_stringio(self):
|
|
|
|
with io.StringIO() as f:
|
|
|
|
safe_write(f, "string")
|
|
|
|
|
|
|
|
def test_bytes_to_bytesio(self):
|
|
|
|
with io.BytesIO() as f:
|
|
|
|
safe_write(f, b"bytes")
|
|
|
|
|
|
|
|
|
2023-05-30 09:06:49 +02:00
|
|
|
if __name__ == "__main__":
|
|
|
|
unittest.main()
|