script handling and string handling

This commit is contained in:
Clemens Schwaighofer
2025-10-24 21:19:41 +09:00
parent 2637e1e42c
commit caf0039de4
7 changed files with 3196 additions and 0 deletions

View File

@@ -0,0 +1,164 @@
"""
PyTest: string_handling/byte_helpers
"""
from corelibs.string_handling.byte_helpers import format_bytes
class TestFormatBytes:
"""Tests for format_bytes function"""
def test_string_input_returned_unchanged(self):
"""Test that string inputs are returned as-is"""
result = format_bytes("already formatted")
assert result == "already formatted"
def test_empty_string_returned_unchanged(self):
"""Test that empty strings are returned as-is"""
result = format_bytes("")
assert result == ""
def test_zero_int(self):
"""Test zero integer returns 0 bytes"""
result = format_bytes(0)
assert result == "0.00 B"
def test_zero_float(self):
"""Test zero float returns 0 bytes"""
result = format_bytes(0.0)
assert result == "0.00 B"
def test_none_value(self):
"""Test None is treated as 0 bytes"""
result = format_bytes(None) # type: ignore[arg-type]
assert result == "0.00 B"
def test_bytes_less_than_1kb(self):
"""Test formatting bytes less than 1KB"""
result = format_bytes(512)
assert result == "512.00 B"
def test_kilobytes(self):
"""Test formatting kilobytes"""
result = format_bytes(1024)
assert result == "1.00 KB"
def test_kilobytes_with_decimals(self):
"""Test formatting kilobytes with decimal values"""
result = format_bytes(1536) # 1.5 KB
assert result == "1.50 KB"
def test_megabytes(self):
"""Test formatting megabytes"""
result = format_bytes(1048576) # 1 MB
assert result == "1.00 MB"
def test_megabytes_with_decimals(self):
"""Test formatting megabytes with decimal values"""
result = format_bytes(2621440) # 2.5 MB
assert result == "2.50 MB"
def test_gigabytes(self):
"""Test formatting gigabytes"""
result = format_bytes(1073741824) # 1 GB
assert result == "1.00 GB"
def test_terabytes(self):
"""Test formatting terabytes"""
result = format_bytes(1099511627776) # 1 TB
assert result == "1.00 TB"
def test_petabytes(self):
"""Test formatting petabytes"""
result = format_bytes(1125899906842624) # 1 PB
assert result == "1.00 PB"
def test_exabytes(self):
"""Test formatting exabytes"""
result = format_bytes(1152921504606846976) # 1 EB
assert result == "1.00 EB"
def test_zettabytes(self):
"""Test formatting zettabytes"""
result = format_bytes(1180591620717411303424) # 1 ZB
assert result == "1.00 ZB"
def test_yottabytes(self):
"""Test formatting yottabytes"""
result = format_bytes(1208925819614629174706176) # 1 YB
assert result == "1.00 YB"
def test_negative_bytes(self):
"""Test formatting negative byte values"""
result = format_bytes(-512)
assert result == "-512.00 B"
def test_negative_kilobytes(self):
"""Test formatting negative kilobytes"""
result = format_bytes(-1024)
assert result == "-1.00 KB"
def test_negative_megabytes(self):
"""Test formatting negative megabytes"""
result = format_bytes(-1048576)
assert result == "-1.00 MB"
def test_float_input_bytes(self):
"""Test float input for bytes"""
result = format_bytes(512.5)
assert result == "512.50 B"
def test_float_input_kilobytes(self):
"""Test float input for kilobytes"""
result = format_bytes(1536.75)
assert result == "1.50 KB"
def test_large_number_formatting(self):
"""Test that large numbers use comma separators"""
result = format_bytes(10240) # 10 KB
assert result == "10.00 KB"
def test_very_large_byte_value(self):
"""Test very large byte value (beyond ZB)"""
result = format_bytes(1208925819614629174706176)
assert result == "1.00 YB"
def test_boundary_1023_bytes(self):
"""Test boundary case just below 1KB"""
result = format_bytes(1023)
assert result == "1,023.00 B"
def test_boundary_1024_bytes(self):
"""Test boundary case at exactly 1KB"""
result = format_bytes(1024)
assert result == "1.00 KB"
def test_int_converted_to_float(self):
"""Test that integer input is properly converted to float"""
result = format_bytes(2048)
assert result == "2.00 KB"
assert "." in result # Verify decimal point is present
def test_small_decimal_value(self):
"""Test small decimal byte value"""
result = format_bytes(0.5)
assert result == "0.50 B"
def test_precision_two_decimals(self):
"""Test that result always has two decimal places"""
result = format_bytes(1024)
assert result == "1.00 KB"
assert result.count('.') == 1
decimal_part = result.split('.')[1].split()[0]
assert len(decimal_part) == 2
def test_mixed_units_progression(self):
"""Test progression through multiple unit levels"""
# Start with bytes
assert "B" in format_bytes(100)
# Move to KB
assert "KB" in format_bytes(100 * 1024)
# Move to MB
assert "MB" in format_bytes(100 * 1024 * 1024)
# Move to GB
assert "GB" in format_bytes(100 * 1024 * 1024 * 1024)

View File

@@ -0,0 +1,524 @@
"""
PyTest: string_handling/double_byte_string_format
"""
import pytest
from corelibs.string_handling.double_byte_string_format import DoubleByteFormatString
class TestDoubleByteFormatStringInit:
"""Tests for DoubleByteFormatString initialization"""
def test_basic_initialization(self):
"""Test basic initialization with string and cut_length"""
formatter = DoubleByteFormatString("Hello World", 10)
assert formatter.string == "Hello World"
assert formatter.cut_length == 10
assert formatter.format_length == 10
assert formatter.placeholder == ".."
def test_initialization_with_format_length(self):
"""Test initialization with both cut_length and format_length"""
formatter = DoubleByteFormatString("Hello World", 5, 15)
assert formatter.cut_length == 5
assert formatter.format_length == 15
def test_initialization_with_custom_placeholder(self):
"""Test initialization with custom placeholder"""
formatter = DoubleByteFormatString("Hello World", 10, placeholder="...")
assert formatter.placeholder == "..."
def test_initialization_with_custom_format_string(self):
"""Test initialization with custom format string"""
formatter = DoubleByteFormatString("Hello", 10, format_string="{{:>{len}}}")
assert formatter.format_string == "{{:>{len}}}"
def test_zero_cut_length_uses_string_width(self):
"""Test that zero cut_length defaults to string width"""
formatter = DoubleByteFormatString("Hello", 0)
assert formatter.cut_length > 0
# For ASCII string, width should equal length
assert formatter.cut_length == 5
def test_negative_cut_length_uses_string_width(self):
"""Test that negative cut_length defaults to string width"""
formatter = DoubleByteFormatString("Hello", -5)
assert formatter.cut_length > 0
def test_cut_length_adjusted_to_format_length(self):
"""Test that cut_length is adjusted when larger than format_length"""
formatter = DoubleByteFormatString("Hello World", 20, 10)
assert formatter.cut_length == 10 # Should be min(20, 10)
def test_none_format_length(self):
"""Test with None format_length"""
formatter = DoubleByteFormatString("Hello", 10, None)
assert formatter.format_length == 10 # Should default to cut_length
class TestDoubleByteFormatStringWithAscii:
"""Tests for ASCII (single-byte) string handling"""
def test_ascii_no_shortening_needed(self):
"""Test ASCII string shorter than cut_length"""
formatter = DoubleByteFormatString("Hello", 10)
assert formatter.get_string_short() == "Hello"
assert formatter.string_short_width == 0 # Not set because no shortening
def test_ascii_exact_cut_length(self):
"""Test ASCII string equal to cut_length"""
formatter = DoubleByteFormatString("Hello", 5)
assert formatter.get_string_short() == "Hello"
def test_ascii_shortening_required(self):
"""Test ASCII string requiring shortening"""
formatter = DoubleByteFormatString("Hello World", 8)
result = formatter.get_string_short()
assert result == "Hello .."
assert len(result) == 8
def test_ascii_with_custom_placeholder(self):
"""Test ASCII shortening with custom placeholder"""
formatter = DoubleByteFormatString("Hello World", 8, placeholder="...")
result = formatter.get_string_short()
assert result.endswith("...")
assert len(result) == 8
def test_ascii_very_short_cut_length(self):
"""Test ASCII with very short cut_length"""
formatter = DoubleByteFormatString("Hello World", 3)
result = formatter.get_string_short()
assert result == "H.."
assert len(result) == 3
def test_ascii_format_length_calculation(self):
"""Test format_length calculation for ASCII strings"""
formatter = DoubleByteFormatString("Hello", 10, 15)
# String is not shortened, format_length should be 15
assert formatter.get_format_length() == 15
class TestDoubleByteFormatStringWithDoubleByte:
"""Tests for double-byte (Asian) character handling"""
def test_japanese_characters(self):
"""Test Japanese string handling"""
formatter = DoubleByteFormatString("こんにちは", 10)
# Each Japanese character is double-width
# "こんにちは" = 5 chars * 2 width = 10 width
assert formatter.get_string_short() == "こんにちは"
def test_japanese_shortening(self):
"""Test Japanese string requiring shortening"""
formatter = DoubleByteFormatString("こんにちは世界", 8)
# Should fit 3 double-width chars (6 width) + placeholder (2 chars)
result = formatter.get_string_short()
assert result.endswith("..")
assert len(result) <= 5 # 3 Japanese chars + 2 placeholder chars
def test_chinese_characters(self):
"""Test Chinese string handling"""
formatter = DoubleByteFormatString("你好世界", 8)
# 4 Chinese chars = 8 width, should fit exactly
assert formatter.get_string_short() == "你好世界"
def test_chinese_shortening(self):
"""Test Chinese string requiring shortening"""
formatter = DoubleByteFormatString("你好世界朋友", 8)
# Should fit 3 double-width chars (6 width) + placeholder (2 chars)
result = formatter.get_string_short()
assert result.endswith("..")
assert len(result) <= 5
def test_korean_characters(self):
"""Test Korean string handling"""
formatter = DoubleByteFormatString("안녕하세요", 10)
# Korean characters are also double-width
assert formatter.get_string_short() == "안녕하세요"
def test_mixed_ascii_japanese(self):
"""Test mixed ASCII and Japanese characters"""
formatter = DoubleByteFormatString("Hello世界", 10)
# "Hello" = 5 width, "世界" = 4 width, total = 9 width
assert formatter.get_string_short() == "Hello世界"
def test_mixed_ascii_japanese_shortening(self):
"""Test mixed string requiring shortening"""
formatter = DoubleByteFormatString("Hello世界Test", 10)
# Should shorten to fit within 10 width
result = formatter.get_string_short()
assert result.endswith("..")
# Total visual width should be <= 10
def test_fullwidth_ascii(self):
"""Test fullwidth ASCII characters"""
# Fullwidth ASCII characters (U+FF01 to U+FF5E)
formatter = DoubleByteFormatString("world", 10)
result = formatter.get_string_short()
assert result.endswith("..")
class TestDoubleByteFormatStringGetters:
"""Tests for getter methods"""
def test_get_string_short(self):
"""Test get_string_short method"""
formatter = DoubleByteFormatString("Hello World", 8)
result = formatter.get_string_short()
assert isinstance(result, str)
assert result == "Hello .."
def test_get_format_length(self):
"""Test get_format_length method"""
formatter = DoubleByteFormatString("Hello", 5, 10)
assert formatter.get_format_length() == 10
def test_get_cut_length(self):
"""Test get_cut_length method"""
formatter = DoubleByteFormatString("Hello", 8)
assert formatter.get_cut_length() == 8
def test_get_requested_cut_length(self):
"""Test get_requested_cut_length method"""
formatter = DoubleByteFormatString("Hello", 15)
assert formatter.get_requested_cut_length() == 15
def test_get_requested_format_length(self):
"""Test get_requested_format_length method"""
formatter = DoubleByteFormatString("Hello", 5, 20)
assert formatter.get_requested_format_length() == 20
def test_get_string_short_formated_default(self):
"""Test get_string_short_formated with default format"""
formatter = DoubleByteFormatString("Hello", 5, 10)
result = formatter.get_string_short_formated()
assert isinstance(result, str)
assert len(result) == 10 # Should be padded to format_length
assert result.startswith("Hello")
def test_get_string_short_formated_custom(self):
"""Test get_string_short_formated with custom format string"""
formatter = DoubleByteFormatString("Hello", 5, 10)
result = formatter.get_string_short_formated("{{:>{len}}}")
assert isinstance(result, str)
assert result.endswith("Hello") # Right-aligned
def test_get_string_short_formated_empty_format_string(self):
"""Test get_string_short_formated with empty format string falls back to default"""
formatter = DoubleByteFormatString("Hello", 5, 10)
result = formatter.get_string_short_formated("")
# Should use default format_string from initialization
assert isinstance(result, str)
class TestDoubleByteFormatStringFormatting:
"""Tests for formatted output"""
def test_format_with_padding(self):
"""Test formatted string with padding"""
formatter = DoubleByteFormatString("Hello", 5, 10)
result = formatter.get_string_short_formated()
assert len(result) == 10
assert result == "Hello " # Left-aligned with spaces
def test_format_shortened_string(self):
"""Test formatted shortened string"""
formatter = DoubleByteFormatString("Hello World", 8, 12)
result = formatter.get_string_short_formated()
# Should be "Hello .." padded to 12
assert len(result) == 12
assert result.startswith("Hello ..")
def test_format_with_double_byte_chars(self):
"""Test formatting with double-byte characters"""
formatter = DoubleByteFormatString("日本語", 6, 10)
result = formatter.get_string_short_formated()
# "日本語" = 3 chars * 2 width = 6 width
# Format should account for visual width difference
assert isinstance(result, str)
def test_format_shortened_double_byte(self):
"""Test formatting shortened double-byte string"""
formatter = DoubleByteFormatString("こんにちは世界", 8, 12)
result = formatter.get_string_short_formated()
assert isinstance(result, str)
# Should be shortened and formatted
class TestDoubleByteFormatStringProcess:
"""Tests for process method"""
def test_process_called_on_init(self):
"""Test that process is called during initialization"""
formatter = DoubleByteFormatString("Hello World", 8)
# process() should have been called, so string_short should be set
assert formatter.string_short != ''
def test_manual_process_call(self):
"""Test calling process manually"""
formatter = DoubleByteFormatString("Hello World", 8)
# Modify internal state
formatter.string = "New String"
# Call process again
formatter.process()
# Should recalculate based on new string
assert formatter.string_short != ''
def test_process_with_empty_string(self):
"""Test process with empty string"""
formatter = DoubleByteFormatString("", 10)
formatter.process()
# Should handle empty string gracefully
assert formatter.string_short == ''
class TestDoubleByteFormatStringEdgeCases:
"""Tests for edge cases"""
def test_empty_string(self):
"""Test with empty string"""
formatter = DoubleByteFormatString("", 10)
assert formatter.get_string_short() == ""
def test_single_character(self):
"""Test with single character"""
formatter = DoubleByteFormatString("A", 5)
assert formatter.get_string_short() == "A"
def test_single_double_byte_character(self):
"""Test with single double-byte character"""
formatter = DoubleByteFormatString("", 5)
assert formatter.get_string_short() == ""
def test_placeholder_only_length(self):
"""Test when cut_length equals placeholder length"""
formatter = DoubleByteFormatString("Hello World", 2)
result = formatter.get_string_short()
assert result == ".."
def test_very_long_string(self):
"""Test with very long string"""
long_string = "A" * 1000
formatter = DoubleByteFormatString(long_string, 10)
result = formatter.get_string_short()
assert len(result) == 10
assert result.endswith("..")
def test_very_long_double_byte_string(self):
"""Test with very long double-byte string"""
long_string = "" * 500
formatter = DoubleByteFormatString(long_string, 10)
result = formatter.get_string_short()
# Should be shortened to fit 10 visual width
assert result.endswith("..")
def test_special_characters(self):
"""Test with special characters"""
formatter = DoubleByteFormatString("Hello!@#$%^&*()", 10)
result = formatter.get_string_short()
assert isinstance(result, str)
def test_newlines_and_tabs(self):
"""Test with newlines and tabs"""
formatter = DoubleByteFormatString("Hello\nWorld\t!", 10)
result = formatter.get_string_short()
assert isinstance(result, str)
def test_unicode_emoji(self):
"""Test with Unicode emoji"""
formatter = DoubleByteFormatString("Hello 👋 World 🌍", 15)
result = formatter.get_string_short()
assert isinstance(result, str)
def test_non_string_input_conversion(self):
"""Test that non-string inputs are converted to string"""
formatter = DoubleByteFormatString(12345, 10) # type: ignore[arg-type]
assert formatter.string == "12345"
assert formatter.get_string_short() == "12345"
def test_none_conversion(self):
"""Test None conversion to string"""
formatter = DoubleByteFormatString(None, 10) # type: ignore[arg-type]
assert formatter.string == "None"
class TestDoubleByteFormatStringWidthCalculation:
"""Tests for width calculation accuracy"""
def test_ascii_width_calculation(self):
"""Test width calculation for ASCII"""
formatter = DoubleByteFormatString("Hello", 10)
formatter.process()
# ASCII characters should have width = length
assert formatter.string_width_value == 5
def test_japanese_width_calculation(self):
"""Test width calculation for Japanese"""
formatter = DoubleByteFormatString("こんにちは", 20)
formatter.process()
# 5 Japanese characters * 2 width each = 10
assert formatter.string_width_value == 10
def test_mixed_width_calculation(self):
"""Test width calculation for mixed characters"""
formatter = DoubleByteFormatString("Hello日本", 20)
formatter.process()
# "Hello" = 5 width, "日本" = 4 width, total = 9
assert formatter.string_width_value == 9
def test_fullwidth_latin_calculation(self):
"""Test width calculation for fullwidth Latin characters"""
# Fullwidth Latin letters
formatter = DoubleByteFormatString("", 10)
formatter.process()
# 3 fullwidth characters * 2 width each = 6
assert formatter.string_width_value == 6
# Parametrized tests
@pytest.mark.parametrize("string,cut_length,expected_short", [
("Hello", 10, "Hello"),
("Hello World", 8, "Hello .."),
("Hello World Test", 5, "Hel.."),
("", 5, ""),
("A", 5, "A"),
])
def test_ascii_shortening_parametrized(string: str, cut_length: int, expected_short: str):
"""Parametrized test for ASCII string shortening"""
formatter = DoubleByteFormatString(string, cut_length)
assert formatter.get_string_short() == expected_short
@pytest.mark.parametrize("string,cut_length,format_length,expected_format_len", [
("Hello", 5, 10, 10),
("Hello", 10, 5, 5),
("Hello World", 8, 12, 12),
])
def test_format_length_parametrized(
string: str,
cut_length: int,
format_length: int,
expected_format_len: int
):
"""Parametrized test for format length"""
formatter = DoubleByteFormatString(string, cut_length, format_length)
assert formatter.get_format_length() == expected_format_len
@pytest.mark.parametrize("string,expected_width", [
("Hello", 5),
("こんにちは", 10), # 5 Japanese chars * 2
("Hello日本", 9), # 5 + 4
("", 0),
("A", 1),
("", 2),
])
def test_width_calculation_parametrized(string: str, expected_width: int):
"""Parametrized test for width calculation"""
formatter = DoubleByteFormatString(string, 100) # Large cut_length to avoid shortening
formatter.process()
if string:
assert formatter.string_width_value == expected_width
else:
assert formatter.string_width_value == 0
@pytest.mark.parametrize("placeholder", [
"..",
"...",
"",
">>>",
"~",
])
def test_custom_placeholder_parametrized(placeholder: str):
"""Parametrized test for custom placeholders"""
formatter = DoubleByteFormatString("Hello World Test", 8, placeholder=placeholder)
result = formatter.get_string_short()
assert result.endswith(placeholder)
assert len(result) == 8
class TestDoubleByteFormatStringIntegration:
"""Integration tests for complete workflows"""
def test_complete_workflow_ascii(self):
"""Test complete workflow with ASCII string"""
formatter = DoubleByteFormatString("Hello World", 8, 12)
short = formatter.get_string_short()
formatted = formatter.get_string_short_formated()
assert short == "Hello .."
assert len(formatted) == 12
assert formatted.startswith("Hello ..")
def test_complete_workflow_japanese(self):
"""Test complete workflow with Japanese string"""
formatter = DoubleByteFormatString("こんにちは世界", 8, 12)
short = formatter.get_string_short()
formatted = formatter.get_string_short_formated()
assert short.endswith("..")
assert isinstance(formatted, str)
def test_complete_workflow_mixed(self):
"""Test complete workflow with mixed characters"""
formatter = DoubleByteFormatString("Hello世界World", 10, 15)
short = formatter.get_string_short()
formatted = formatter.get_string_short_formated()
assert short.endswith("..")
assert isinstance(formatted, str)
def test_table_like_output(self):
"""Test creating table-like output with multiple formatters"""
items = [
("Name", "Alice", 10, 15),
("City", "Tokyo東京", 10, 15),
("Country", "Japan日本国", 10, 15),
]
results: list[str] = []
for _label, value, cut, fmt in items:
formatter = DoubleByteFormatString(value, cut, fmt)
results.append(formatter.get_string_short_formated())
# All results should be formatted strings
# Note: Due to double-byte character width adjustments,
# the actual string length may differ from format_length
assert all(isinstance(result, str) for result in results)
assert all(len(result) > 0 for result in results)
def test_reprocess_after_modification(self):
"""Test reprocessing after modifying formatter properties"""
formatter = DoubleByteFormatString("Hello World", 8, 12)
initial = formatter.get_string_short()
# Modify and reprocess
formatter.string = "New String Test"
formatter.process()
modified = formatter.get_string_short()
assert initial != modified
assert modified.endswith("..")
class TestDoubleByteFormatStringRightAlignment:
"""Tests for right-aligned formatting"""
def test_right_aligned_format(self):
"""Test right-aligned formatting"""
formatter = DoubleByteFormatString("Hello", 5, 10, format_string="{{:>{len}}}")
result = formatter.get_string_short_formated()
assert len(result) == 10
# The format applies to the short string
assert "Hello" in result
def test_center_aligned_format(self):
"""Test center-aligned formatting"""
formatter = DoubleByteFormatString("Hello", 5, 11, format_string="{{:^{len}}}")
result = formatter.get_string_short_formated()
assert len(result) == 11
assert "Hello" in result
# __END__

View File

@@ -0,0 +1,328 @@
"""
PyTest: string_handling/hash_helpers
"""
import pytest
from corelibs.string_handling.hash_helpers import (
crc32b_fix, sha1_short
)
class TestCrc32bFix:
"""Tests for crc32b_fix function"""
def test_basic_crc_fix(self):
"""Test basic CRC32B byte order fix"""
# Example: if input is "abcdefgh", it should become "ghefcdab"
result = crc32b_fix("abcdefgh")
assert result == "ghefcdab"
def test_short_crc_padding(self):
"""Test that short CRC is left-padded with zeros"""
# Input with 6 chars should be padded to 8: "00abcdef"
# Split into pairs: "00", "ab", "cd", "ef"
# Reversed: "ef", "cd", "ab", "00"
result = crc32b_fix("abcdef")
assert result == "efcdab00"
assert len(result) == 8
def test_4_char_crc(self):
"""Test CRC with 4 characters"""
# Padded: "0000abcd"
# Pairs: "00", "00", "ab", "cd"
# Reversed: "cd", "ab", "00", "00"
result = crc32b_fix("abcd")
assert result == "cdab0000"
assert len(result) == 8
def test_2_char_crc(self):
"""Test CRC with 2 characters"""
# Padded: "000000ab"
# Pairs: "00", "00", "00", "ab"
# Reversed: "ab", "00", "00", "00"
result = crc32b_fix("ab")
assert result == "ab000000"
assert len(result) == 8
def test_1_char_crc(self):
"""Test CRC with 1 character"""
# Padded: "0000000a"
# Pairs: "00", "00", "00", "0a"
# Reversed: "0a", "00", "00", "00"
result = crc32b_fix("a")
assert result == "0a000000"
assert len(result) == 8
def test_empty_crc(self):
"""Test empty CRC string"""
result = crc32b_fix("")
assert result == "00000000"
assert len(result) == 8
def test_numeric_crc(self):
"""Test CRC with numeric characters"""
result = crc32b_fix("12345678")
assert result == "78563412"
def test_mixed_alphanumeric(self):
"""Test CRC with mixed alphanumeric characters"""
result = crc32b_fix("a1b2c3d4")
assert result == "d4c3b2a1"
def test_lowercase_letters(self):
"""Test CRC with lowercase letters"""
result = crc32b_fix("aabbccdd")
assert result == "ddccbbaa"
def test_with_numbers_and_letters(self):
"""Test CRC with numbers and letters (typical hex)"""
result = crc32b_fix("1a2b3c4d")
assert result == "4d3c2b1a"
def test_all_zeros(self):
"""Test CRC with all zeros"""
result = crc32b_fix("00000000")
assert result == "00000000"
def test_short_padding_all_numbers(self):
"""Test padding with all numbers"""
# Padded: "00123456"
# Pairs: "00", "12", "34", "56"
# Reversed: "56", "34", "12", "00"
result = crc32b_fix("123456")
assert result == "56341200"
assert len(result) == 8
def test_typical_hex_values(self):
"""Test with typical hexadecimal hash values"""
result = crc32b_fix("a1b2c3d4")
assert result == "d4c3b2a1"
def test_7_char_crc(self):
"""Test CRC with 7 characters (needs 1 zero padding)"""
# Padded: "0abcdefg"
# Pairs: "0a", "bc", "de", "fg"
# Reversed: "fg", "de", "bc", "0a"
result = crc32b_fix("abcdefg")
assert result == "fgdebc0a"
assert len(result) == 8
class TestSha1Short:
"""Tests for sha1_short function"""
def test_basic_sha1_short(self):
"""Test basic SHA1 short hash generation"""
result = sha1_short("hello")
assert len(result) == 9
assert result.isalnum() # Should be hexadecimal
def test_consistent_output(self):
"""Test that same input produces same output"""
result1 = sha1_short("test")
result2 = sha1_short("test")
assert result1 == result2
def test_different_inputs_different_outputs(self):
"""Test that different inputs produce different outputs"""
result1 = sha1_short("hello")
result2 = sha1_short("world")
assert result1 != result2
def test_empty_string(self):
"""Test SHA1 of empty string"""
result = sha1_short("")
assert len(result) == 9
# SHA1 of empty string is known: "da39a3ee5e6b4b0d3255bfef95601890afd80709"
assert result == "da39a3ee5"
def test_single_character(self):
"""Test SHA1 of single character"""
result = sha1_short("a")
assert len(result) == 9
# SHA1 of "a" is "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"
assert result == "86f7e437f"
def test_long_string(self):
"""Test SHA1 of long string"""
long_string = "a" * 1000
result = sha1_short(long_string)
assert len(result) == 9
assert result.isalnum()
def test_special_characters(self):
"""Test SHA1 with special characters"""
result = sha1_short("hello@world!")
assert len(result) == 9
assert result.isalnum()
def test_unicode_characters(self):
"""Test SHA1 with unicode characters"""
result = sha1_short("こんにちは")
assert len(result) == 9
assert result.isalnum()
def test_numbers(self):
"""Test SHA1 with numeric string"""
result = sha1_short("12345")
assert len(result) == 9
assert result.isalnum()
def test_whitespace(self):
"""Test SHA1 with whitespace"""
result1 = sha1_short("hello world")
result2 = sha1_short("helloworld")
assert result1 != result2
assert len(result1) == 9
assert len(result2) == 9
def test_newlines_and_tabs(self):
"""Test SHA1 with newlines and tabs"""
result = sha1_short("hello\nworld\ttab")
assert len(result) == 9
assert result.isalnum()
def test_mixed_case(self):
"""Test SHA1 with mixed case (should be case sensitive)"""
result1 = sha1_short("Hello")
result2 = sha1_short("hello")
assert result1 != result2
def test_hexadecimal_output(self):
"""Test that output is valid hexadecimal"""
result = sha1_short("test")
# Should only contain 0-9 and a-f
assert all(c in "0123456789abcdef" for c in result)
def test_known_value_verification(self):
"""Test against known SHA1 values"""
# SHA1 of "hello" is "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
result = sha1_short("hello")
assert result == "aaf4c61dd"
def test_numeric_string_input(self):
"""Test with numeric string"""
result = sha1_short("123456789")
assert len(result) == 9
assert result.isalnum()
def test_emoji_input(self):
"""Test with emoji characters"""
result = sha1_short("😀🎉")
assert len(result) == 9
assert result.isalnum()
def test_multiline_string(self):
"""Test with multiline string"""
multiline = """This is
a multiline
string"""
result = sha1_short(multiline)
assert len(result) == 9
assert result.isalnum()
# Parametrized tests
@pytest.mark.parametrize("input_crc,expected", [
("abcdefgh", "ghefcdab"),
("12345678", "78563412"),
("aabbccdd", "ddccbbaa"),
("00000000", "00000000"),
("", "00000000"),
("a", "0a000000"),
("ab", "ab000000"),
("abcd", "cdab0000"),
("abcdef", "efcdab00"),
])
def test_crc32b_fix_parametrized(input_crc: str, expected: str):
"""Parametrized test for crc32b_fix"""
result = crc32b_fix(input_crc)
assert len(result) == 8
assert result == expected
@pytest.mark.parametrize("input_string,expected_length", [
("hello", 9),
("world", 9),
("", 9),
("a" * 1000, 9),
("test123", 9),
("😀", 9),
])
def test_sha1_short_parametrized_length(input_string: str, expected_length: int):
"""Parametrized test for sha1_short to verify consistent length"""
result = sha1_short(input_string)
assert len(result) == expected_length
@pytest.mark.parametrize("input_string,expected_hash", [
("", "da39a3ee5"),
("a", "86f7e437f"),
("hello", "aaf4c61dd"),
("world", "7c211433f"),
("test", "a94a8fe5c"),
])
def test_sha1_short_known_values(input_string: str, expected_hash: str):
"""Parametrized test for sha1_short with known SHA1 values"""
result = sha1_short(input_string)
assert result == expected_hash
# Edge case tests
class TestEdgeCases:
"""Test edge cases for hash helper functions"""
def test_crc32b_fix_with_max_length(self):
"""Test crc32b_fix with exactly 8 characters"""
result = crc32b_fix("ffffffff")
assert result == "ffffffff"
assert len(result) == 8
def test_sha1_short_very_long_input(self):
"""Test sha1_short with very long input"""
very_long = "x" * 10000
result = sha1_short(very_long)
assert len(result) == 9
assert result.isalnum()
def test_sha1_short_binary_like_string(self):
"""Test sha1_short with binary-like string"""
result = sha1_short("\x00\x01\x02\x03")
assert len(result) == 9
assert result.isalnum()
def test_crc32b_fix_preserves_characters(self):
"""Test that crc32b_fix only reorders, doesn't change characters"""
input_crc = "12345678"
result = crc32b_fix(input_crc)
# All characters from input should be in output (after padding)
for char in input_crc:
assert char in result or '0' in result # 0 is for padding
# Integration tests
class TestIntegration:
"""Integration tests for hash helper functions"""
def test_sha1_short_produces_valid_crc_input(self):
"""Test that sha1_short output could be used as CRC input"""
sha1_result = sha1_short("test")
# SHA1 short is 9 chars, CRC expects up to 8, so take first 8
crc_input = sha1_result[:8]
crc_result = crc32b_fix(crc_input)
assert len(crc_result) == 8
def test_multiple_sha1_short_consistency(self):
"""Test that multiple calls to sha1_short are consistent"""
results = [sha1_short("consistency_test") for _ in range(10)]
assert all(r == results[0] for r in results)
def test_crc32b_fix_reversibility_concept(self):
"""Test that applying crc32b_fix twice reverses the operation"""
original = "abcdefgh"
fixed_once = crc32b_fix(original)
fixed_twice = crc32b_fix(fixed_once)
assert fixed_twice == original
# __END__

View File

@@ -0,0 +1,516 @@
"""
PyTest: string_handling/text_colors
"""
import pytest
from corelibs.string_handling.text_colors import Colors
class TestColorsInitialState:
"""Tests for Colors class initial state"""
def test_bold_initial_value(self):
"""Test that bold has correct ANSI code"""
assert Colors.bold == '\033[1m'
def test_underline_initial_value(self):
"""Test that underline has correct ANSI code"""
assert Colors.underline == '\033[4m'
def test_end_initial_value(self):
"""Test that end has correct ANSI code"""
assert Colors.end == '\033[0m'
def test_reset_initial_value(self):
"""Test that reset has correct ANSI code"""
assert Colors.reset == '\033[0m'
class TestColorsNormal:
"""Tests for normal color ANSI codes"""
def test_black_normal(self):
"""Test black color code"""
assert Colors.black == "\033[30m"
def test_red_normal(self):
"""Test red color code"""
assert Colors.red == "\033[31m"
def test_green_normal(self):
"""Test green color code"""
assert Colors.green == "\033[32m"
def test_yellow_normal(self):
"""Test yellow color code"""
assert Colors.yellow == "\033[33m"
def test_blue_normal(self):
"""Test blue color code"""
assert Colors.blue == "\033[34m"
def test_magenta_normal(self):
"""Test magenta color code"""
assert Colors.magenta == "\033[35m"
def test_cyan_normal(self):
"""Test cyan color code"""
assert Colors.cyan == "\033[36m"
def test_white_normal(self):
"""Test white color code"""
assert Colors.white == "\033[37m"
class TestColorsBold:
"""Tests for bold color ANSI codes"""
def test_black_bold(self):
"""Test black bold color code"""
assert Colors.black_bold == "\033[1;30m"
def test_red_bold(self):
"""Test red bold color code"""
assert Colors.red_bold == "\033[1;31m"
def test_green_bold(self):
"""Test green bold color code"""
assert Colors.green_bold == "\033[1;32m"
def test_yellow_bold(self):
"""Test yellow bold color code"""
assert Colors.yellow_bold == "\033[1;33m"
def test_blue_bold(self):
"""Test blue bold color code"""
assert Colors.blue_bold == "\033[1;34m"
def test_magenta_bold(self):
"""Test magenta bold color code"""
assert Colors.magenta_bold == "\033[1;35m"
def test_cyan_bold(self):
"""Test cyan bold color code"""
assert Colors.cyan_bold == "\033[1;36m"
def test_white_bold(self):
"""Test white bold color code"""
assert Colors.white_bold == "\033[1;37m"
class TestColorsBright:
"""Tests for bright color ANSI codes"""
def test_black_bright(self):
"""Test black bright color code"""
assert Colors.black_bright == '\033[90m'
def test_red_bright(self):
"""Test red bright color code"""
assert Colors.red_bright == '\033[91m'
def test_green_bright(self):
"""Test green bright color code"""
assert Colors.green_bright == '\033[92m'
def test_yellow_bright(self):
"""Test yellow bright color code"""
assert Colors.yellow_bright == '\033[93m'
def test_blue_bright(self):
"""Test blue bright color code"""
assert Colors.blue_bright == '\033[94m'
def test_magenta_bright(self):
"""Test magenta bright color code"""
assert Colors.magenta_bright == '\033[95m'
def test_cyan_bright(self):
"""Test cyan bright color code"""
assert Colors.cyan_bright == '\033[96m'
def test_white_bright(self):
"""Test white bright color code"""
assert Colors.white_bright == '\033[97m'
class TestColorsDisable:
"""Tests for Colors.disable() method"""
def setup_method(self):
"""Reset colors before each test"""
Colors.reset_colors()
def teardown_method(self):
"""Reset colors after each test"""
Colors.reset_colors()
def test_disable_bold_and_underline(self):
"""Test that disable() sets bold and underline to empty strings"""
Colors.disable()
assert Colors.bold == ''
assert Colors.underline == ''
def test_disable_end_and_reset(self):
"""Test that disable() sets end and reset to empty strings"""
Colors.disable()
assert Colors.end == ''
assert Colors.reset == ''
def test_disable_normal_colors(self):
"""Test that disable() sets all normal colors to empty strings"""
Colors.disable()
assert Colors.black == ''
assert Colors.red == ''
assert Colors.green == ''
assert Colors.yellow == ''
assert Colors.blue == ''
assert Colors.magenta == ''
assert Colors.cyan == ''
assert Colors.white == ''
def test_disable_bold_colors(self):
"""Test that disable() sets all bold colors to empty strings"""
Colors.disable()
assert Colors.black_bold == ''
assert Colors.red_bold == ''
assert Colors.green_bold == ''
assert Colors.yellow_bold == ''
assert Colors.blue_bold == ''
assert Colors.magenta_bold == ''
assert Colors.cyan_bold == ''
assert Colors.white_bold == ''
def test_disable_bright_colors(self):
"""Test that disable() sets all bright colors to empty strings"""
Colors.disable()
assert Colors.black_bright == ''
assert Colors.red_bright == ''
assert Colors.green_bright == ''
assert Colors.yellow_bright == ''
assert Colors.blue_bright == ''
assert Colors.magenta_bright == ''
assert Colors.cyan_bright == ''
assert Colors.white_bright == ''
def test_disable_all_colors_at_once(self):
"""Test that all color attributes are empty after disable()"""
Colors.disable()
# Check that all public attributes are empty strings
for attr in dir(Colors):
if not attr.startswith('_') and attr not in ['disable', 'reset_colors']:
assert getattr(Colors, attr) == '', f"{attr} should be empty after disable()"
class TestColorsResetColors:
"""Tests for Colors.reset_colors() method"""
def setup_method(self):
"""Disable colors before each test"""
Colors.disable()
def teardown_method(self):
"""Reset colors after each test"""
Colors.reset_colors()
def test_reset_bold_and_underline(self):
"""Test that reset_colors() restores bold and underline"""
Colors.reset_colors()
assert Colors.bold == '\033[1m'
assert Colors.underline == '\033[4m'
def test_reset_end_and_reset(self):
"""Test that reset_colors() restores end and reset"""
Colors.reset_colors()
assert Colors.end == '\033[0m'
assert Colors.reset == '\033[0m'
def test_reset_normal_colors(self):
"""Test that reset_colors() restores all normal colors"""
Colors.reset_colors()
assert Colors.black == "\033[30m"
assert Colors.red == "\033[31m"
assert Colors.green == "\033[32m"
assert Colors.yellow == "\033[33m"
assert Colors.blue == "\033[34m"
assert Colors.magenta == "\033[35m"
assert Colors.cyan == "\033[36m"
assert Colors.white == "\033[37m"
def test_reset_bold_colors(self):
"""Test that reset_colors() restores all bold colors"""
Colors.reset_colors()
assert Colors.black_bold == "\033[1;30m"
assert Colors.red_bold == "\033[1;31m"
assert Colors.green_bold == "\033[1;32m"
assert Colors.yellow_bold == "\033[1;33m"
assert Colors.blue_bold == "\033[1;34m"
assert Colors.magenta_bold == "\033[1;35m"
assert Colors.cyan_bold == "\033[1;36m"
assert Colors.white_bold == "\033[1;37m"
def test_reset_bright_colors(self):
"""Test that reset_colors() restores all bright colors"""
Colors.reset_colors()
assert Colors.black_bright == '\033[90m'
assert Colors.red_bright == '\033[91m'
assert Colors.green_bright == '\033[92m'
assert Colors.yellow_bright == '\033[93m'
assert Colors.blue_bright == '\033[94m'
assert Colors.magenta_bright == '\033[95m'
assert Colors.cyan_bright == '\033[96m'
assert Colors.white_bright == '\033[97m'
class TestColorsDisableAndReset:
"""Tests for disable and reset cycle"""
def setup_method(self):
"""Reset colors before each test"""
Colors.reset_colors()
def teardown_method(self):
"""Reset colors after each test"""
Colors.reset_colors()
def test_disable_then_reset_cycle(self):
"""Test that colors can be disabled and then reset multiple times"""
# Initial state
original_red = Colors.red
# Disable
Colors.disable()
assert Colors.red == ''
# Reset
Colors.reset_colors()
assert Colors.red == original_red
# Disable again
Colors.disable()
assert Colors.red == ''
# Reset again
Colors.reset_colors()
assert Colors.red == original_red
def test_multiple_disables(self):
"""Test that calling disable() multiple times is safe"""
Colors.disable()
Colors.disable()
Colors.disable()
assert Colors.red == ''
assert Colors.blue == ''
def test_multiple_resets(self):
"""Test that calling reset_colors() multiple times is safe"""
Colors.reset_colors()
Colors.reset_colors()
Colors.reset_colors()
assert Colors.red == "\033[31m"
assert Colors.blue == "\033[34m"
class TestColorsUsage:
"""Tests for practical usage of Colors class"""
def setup_method(self):
"""Reset colors before each test"""
Colors.reset_colors()
def teardown_method(self):
"""Reset colors after each test"""
Colors.reset_colors()
def test_colored_string_with_reset(self):
"""Test creating a colored string with reset"""
result = f"{Colors.red}Error{Colors.end}"
assert result == "\033[31mError\033[0m"
def test_bold_colored_string(self):
"""Test creating a bold colored string"""
result = f"{Colors.bold}{Colors.yellow}Warning{Colors.end}"
assert result == "\033[1m\033[33mWarning\033[0m"
def test_underline_colored_string(self):
"""Test creating an underlined colored string"""
result = f"{Colors.underline}{Colors.blue}Info{Colors.end}"
assert result == "\033[4m\033[34mInfo\033[0m"
def test_bold_underline_colored_string(self):
"""Test creating a bold and underlined colored string"""
result = f"{Colors.bold}{Colors.underline}{Colors.green}Success{Colors.end}"
assert result == "\033[1m\033[4m\033[32mSuccess\033[0m"
def test_multiple_colors_in_string(self):
"""Test using multiple colors in one string"""
result = f"{Colors.red}Red{Colors.end} {Colors.blue}Blue{Colors.end}"
assert result == "\033[31mRed\033[0m \033[34mBlue\033[0m"
def test_bright_color_usage(self):
"""Test using bright color variants"""
result = f"{Colors.cyan_bright}Bright Cyan{Colors.end}"
assert result == "\033[96mBright Cyan\033[0m"
def test_bold_color_shortcut(self):
"""Test using bold color shortcuts"""
result = f"{Colors.red_bold}Bold Red{Colors.end}"
assert result == "\033[1;31mBold Red\033[0m"
def test_disabled_colors_produce_plain_text(self):
"""Test that disabled colors produce plain text without ANSI codes"""
Colors.disable()
result = f"{Colors.red}Error{Colors.end}"
assert result == "Error"
assert "\033[" not in result
def test_disabled_bold_underline_produce_plain_text(self):
"""Test that disabled formatting produces plain text"""
Colors.disable()
result = f"{Colors.bold}{Colors.underline}{Colors.green}Success{Colors.end}"
assert result == "Success"
assert "\033[" not in result
class TestColorsPrivateAttributes:
"""Tests to ensure private attributes are not directly accessible"""
def test_private_bold_not_accessible(self):
"""Test that __BOLD is private"""
with pytest.raises(AttributeError):
_ = Colors.__BOLD
def test_private_colors_not_accessible(self):
"""Test that private color attributes are not accessible"""
with pytest.raises(AttributeError):
_ = Colors.__RED
with pytest.raises(AttributeError):
_ = Colors.__GREEN
# Parametrized tests
@pytest.mark.parametrize("color_attr,expected_code", [
("black", "\033[30m"),
("red", "\033[31m"),
("green", "\033[32m"),
("yellow", "\033[33m"),
("blue", "\033[34m"),
("magenta", "\033[35m"),
("cyan", "\033[36m"),
("white", "\033[37m"),
])
def test_normal_colors_parametrized(color_attr: str, expected_code: str):
"""Parametrized test for normal colors"""
Colors.reset_colors()
assert getattr(Colors, color_attr) == expected_code
@pytest.mark.parametrize("color_attr,expected_code", [
("black_bold", "\033[1;30m"),
("red_bold", "\033[1;31m"),
("green_bold", "\033[1;32m"),
("yellow_bold", "\033[1;33m"),
("blue_bold", "\033[1;34m"),
("magenta_bold", "\033[1;35m"),
("cyan_bold", "\033[1;36m"),
("white_bold", "\033[1;37m"),
])
def test_bold_colors_parametrized(color_attr: str, expected_code: str):
"""Parametrized test for bold colors"""
Colors.reset_colors()
assert getattr(Colors, color_attr) == expected_code
@pytest.mark.parametrize("color_attr,expected_code", [
("black_bright", '\033[90m'),
("red_bright", '\033[91m'),
("green_bright", '\033[92m'),
("yellow_bright", '\033[93m'),
("blue_bright", '\033[94m'),
("magenta_bright", '\033[95m'),
("cyan_bright", '\033[96m'),
("white_bright", '\033[97m'),
])
def test_bright_colors_parametrized(color_attr: str, expected_code: str):
"""Parametrized test for bright colors"""
Colors.reset_colors()
assert getattr(Colors, color_attr) == expected_code
@pytest.mark.parametrize("color_attr", [
"bold", "underline", "end", "reset",
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white",
"black_bold", "red_bold", "green_bold", "yellow_bold",
"blue_bold", "magenta_bold", "cyan_bold", "white_bold",
"black_bright", "red_bright", "green_bright", "yellow_bright",
"blue_bright", "magenta_bright", "cyan_bright", "white_bright",
])
def test_disable_all_attributes_parametrized(color_attr: str):
"""Parametrized test that all color attributes are disabled"""
Colors.reset_colors()
Colors.disable()
assert getattr(Colors, color_attr) == ''
@pytest.mark.parametrize("color_attr", [
"bold", "underline", "end", "reset",
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white",
"black_bold", "red_bold", "green_bold", "yellow_bold",
"blue_bold", "magenta_bold", "cyan_bold", "white_bold",
"black_bright", "red_bright", "green_bright", "yellow_bright",
"blue_bright", "magenta_bright", "cyan_bright", "white_bright",
])
def test_reset_all_attributes_parametrized(color_attr: str):
"""Parametrized test that all color attributes are reset"""
Colors.disable()
Colors.reset_colors()
assert getattr(Colors, color_attr) != ''
assert '\033[' in getattr(Colors, color_attr)
# Edge case tests
class TestColorsEdgeCases:
"""Tests for edge cases and special scenarios"""
def setup_method(self):
"""Reset colors before each test"""
Colors.reset_colors()
def teardown_method(self):
"""Reset colors after each test"""
Colors.reset_colors()
def test_colors_class_is_not_instantiable(self):
"""Test that Colors class can be instantiated (it's not abstract)"""
# The class uses static methods, but can be instantiated
instance = Colors()
assert isinstance(instance, Colors)
def test_static_methods_work_on_instance(self):
"""Test that static methods work when called on instance"""
instance = Colors()
instance.disable()
assert Colors.red == ''
instance.reset_colors()
assert Colors.red == "\033[31m"
def test_concatenation_of_multiple_effects(self):
"""Test concatenating multiple color effects"""
result = f"{Colors.bold}{Colors.underline}{Colors.red_bright}Test{Colors.reset}"
assert "\033[1m" in result # bold
assert "\033[4m" in result # underline
assert "\033[91m" in result # red bright
assert "\033[0m" in result # reset
def test_empty_string_with_colors(self):
"""Test applying colors to empty string"""
result = f"{Colors.red}{Colors.end}"
assert result == "\033[31m\033[0m"
def test_nested_color_changes(self):
"""Test nested color changes in string"""
result = f"{Colors.red}Red {Colors.blue}Blue{Colors.end} Red again{Colors.end}"
assert result == "\033[31mRed \033[34mBlue\033[0m Red again\033[0m"
# __END__