Apply black formatter to all Python files
Reformatted 29 files for consistent code style and CI compliance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -41,8 +41,8 @@ def sample_images(temp_dir):
|
||||
images = []
|
||||
for i in range(3):
|
||||
img_path = temp_dir / f"test_image_{i}.png"
|
||||
img = Image.new('RGB', (100, 100), color=(i * 50, i * 50, i * 50))
|
||||
img.save(img_path, 'PNG')
|
||||
img = Image.new("RGB", (100, 100), color=(i * 50, i * 50, i * 50))
|
||||
img.save(img_path, "PNG")
|
||||
images.append(img_path)
|
||||
|
||||
return images
|
||||
@@ -55,9 +55,9 @@ def sample_reference_photo():
|
||||
|
||||
from PIL import Image
|
||||
|
||||
img = Image.new('RGB', (100, 100), color=(128, 128, 128))
|
||||
img = Image.new("RGB", (100, 100), color=(128, 128, 128))
|
||||
buf = BytesIO()
|
||||
img.save(buf, 'PNG')
|
||||
img.save(buf, "PNG")
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ def sample_credentials(sample_reference_photo):
|
||||
return {
|
||||
"reference_photo": sample_reference_photo,
|
||||
"passphrase": "test phrase four words", # v3.2.0: single passphrase
|
||||
"pin": "123456"
|
||||
"pin": "123456",
|
||||
}
|
||||
|
||||
|
||||
@@ -95,9 +95,9 @@ class TestBatchItem:
|
||||
message="Done",
|
||||
)
|
||||
result = item.to_dict()
|
||||
assert result['input_path'] == "input.png"
|
||||
assert result['output_path'] == "output.png"
|
||||
assert result['status'] == "success"
|
||||
assert result["input_path"] == "input.png"
|
||||
assert result["output_path"] == "output.png"
|
||||
assert result["status"] == "success"
|
||||
|
||||
|
||||
class TestBatchResult:
|
||||
@@ -106,11 +106,12 @@ class TestBatchResult:
|
||||
def test_to_json(self):
|
||||
"""Should serialize to valid JSON."""
|
||||
import json
|
||||
|
||||
result = BatchResult(operation="encode", total=5, succeeded=4, failed=1)
|
||||
json_str = result.to_json()
|
||||
parsed = json.loads(json_str)
|
||||
assert parsed['operation'] == "encode"
|
||||
assert parsed['summary']['total'] == 5
|
||||
assert parsed["operation"] == "encode"
|
||||
assert parsed["summary"]["total"] == 5
|
||||
|
||||
def test_duration_with_end_time(self):
|
||||
"""Duration should work when end_time is set."""
|
||||
@@ -128,7 +129,7 @@ class TestBatchCredentials:
|
||||
data = {
|
||||
"reference_photo": sample_reference_photo,
|
||||
"passphrase": "test phrase four words",
|
||||
"pin": "123456"
|
||||
"pin": "123456",
|
||||
}
|
||||
creds = BatchCredentials.from_dict(data)
|
||||
assert creds.passphrase == "test phrase four words"
|
||||
@@ -139,7 +140,7 @@ class TestBatchCredentials:
|
||||
data = {
|
||||
"reference_photo": sample_reference_photo,
|
||||
"day_phrase": "legacy phrase here", # Old key name
|
||||
"pin": "123456"
|
||||
"pin": "123456",
|
||||
}
|
||||
creds = BatchCredentials.from_dict(data)
|
||||
# Should accept old key and map to passphrase
|
||||
@@ -151,19 +152,19 @@ class TestBatchCredentials:
|
||||
creds = BatchCredentials(
|
||||
reference_photo=sample_reference_photo,
|
||||
passphrase="test phrase four words",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
result = creds.to_dict()
|
||||
assert result['passphrase'] == "test phrase four words"
|
||||
assert result['pin'] == "123456"
|
||||
assert 'day_phrase' not in result # Old key should not be present
|
||||
assert result["passphrase"] == "test phrase four words"
|
||||
assert result["pin"] == "123456"
|
||||
assert "day_phrase" not in result # Old key should not be present
|
||||
|
||||
def test_passphrase_is_string(self, sample_reference_photo):
|
||||
"""Passphrase should be a string, not a dict."""
|
||||
creds = BatchCredentials(
|
||||
reference_photo=sample_reference_photo,
|
||||
passphrase="test phrase four words",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
assert isinstance(creds.passphrase, str)
|
||||
|
||||
@@ -216,7 +217,7 @@ class TestBatchProcessor:
|
||||
nested = temp_dir / "nested"
|
||||
nested.mkdir()
|
||||
img_path = nested / "nested.png"
|
||||
img = Image.new('RGB', (50, 50))
|
||||
img = Image.new("RGB", (50, 50))
|
||||
img.save(img_path)
|
||||
|
||||
processor = BatchProcessor()
|
||||
@@ -241,7 +242,9 @@ class TestBatchProcessor:
|
||||
message="test",
|
||||
)
|
||||
|
||||
def test_batch_encode_accepts_passphrase_credentials(self, sample_images, temp_dir, sample_credentials):
|
||||
def test_batch_encode_accepts_passphrase_credentials(
|
||||
self, sample_images, temp_dir, sample_credentials
|
||||
):
|
||||
"""Should accept v3.2.0 format credentials with passphrase."""
|
||||
processor = BatchProcessor()
|
||||
result = processor.batch_encode(
|
||||
@@ -343,9 +346,9 @@ class TestBatchCapacityCheck:
|
||||
"""Results should include capacity info."""
|
||||
results = batch_capacity_check(sample_images)
|
||||
for item in results:
|
||||
assert 'capacity_bytes' in item
|
||||
assert 'dimensions' in item
|
||||
assert 'valid' in item
|
||||
assert "capacity_bytes" in item
|
||||
assert "dimensions" in item
|
||||
assert "valid" in item
|
||||
|
||||
def test_handles_invalid_files(self, temp_dir):
|
||||
"""Should handle non-image files gracefully."""
|
||||
@@ -354,7 +357,7 @@ class TestBatchCapacityCheck:
|
||||
|
||||
results = batch_capacity_check([bad_file])
|
||||
assert len(results) == 1
|
||||
assert 'error' in results[0]
|
||||
assert "error" in results[0]
|
||||
|
||||
|
||||
class TestPrintBatchResult:
|
||||
@@ -403,7 +406,7 @@ class TestCredentialsMigration:
|
||||
old_format = {
|
||||
"reference_photo": sample_reference_photo,
|
||||
"phrase": "old style phrase",
|
||||
"pin": "123456"
|
||||
"pin": "123456",
|
||||
}
|
||||
# Should not raise
|
||||
creds = BatchCredentials.from_dict(old_format)
|
||||
@@ -414,7 +417,7 @@ class TestCredentialsMigration:
|
||||
old_format = {
|
||||
"reference_photo": sample_reference_photo,
|
||||
"day_phrase": "old day phrase",
|
||||
"pin": "123456"
|
||||
"pin": "123456",
|
||||
}
|
||||
creds = BatchCredentials.from_dict(old_format)
|
||||
assert creds.passphrase == "old day phrase"
|
||||
@@ -425,7 +428,7 @@ class TestCredentialsMigration:
|
||||
"reference_photo": sample_reference_photo,
|
||||
"passphrase": "new style passphrase",
|
||||
"day_phrase": "old day phrase",
|
||||
"pin": "123456"
|
||||
"pin": "123456",
|
||||
}
|
||||
creds = BatchCredentials.from_dict(mixed_format)
|
||||
assert creds.passphrase == "new style passphrase"
|
||||
|
||||
@@ -42,6 +42,7 @@ class TestCompress:
|
||||
def test_compress_incompressible_data(self):
|
||||
"""Incompressible data should be stored uncompressed."""
|
||||
import os
|
||||
|
||||
# Random data doesn't compress well
|
||||
data = os.urandom(500)
|
||||
result = compress(data, CompressionAlgorithm.ZLIB)
|
||||
@@ -107,6 +108,7 @@ class TestDecompress:
|
||||
def test_roundtrip_large_data(self):
|
||||
"""Large data should survive compress/decompress roundtrip."""
|
||||
import os
|
||||
|
||||
original = os.urandom(50000)
|
||||
compressed = compress(original)
|
||||
result = decompress(compressed)
|
||||
@@ -173,7 +175,7 @@ class TestEdgeCases:
|
||||
def test_unicode_after_encoding(self):
|
||||
"""UTF-8 encoded Unicode should compress correctly."""
|
||||
text = "Hello, 世界! 🎉 " * 100
|
||||
data = text.encode('utf-8')
|
||||
data = text.encode("utf-8")
|
||||
compressed = compress(data)
|
||||
result = decompress(compressed)
|
||||
assert result.decode('utf-8') == text
|
||||
assert result.decode("utf-8") == text
|
||||
|
||||
@@ -37,12 +37,13 @@ from stegasoo.steganography import get_output_format
|
||||
# Fixtures
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def png_image():
|
||||
"""Create a test PNG image."""
|
||||
img = Image.new('RGB', (100, 100), color='red')
|
||||
img = Image.new("RGB", (100, 100), color="red")
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format='PNG')
|
||||
img.save(buf, format="PNG")
|
||||
buf.seek(0)
|
||||
return buf.getvalue()
|
||||
|
||||
@@ -50,9 +51,9 @@ def png_image():
|
||||
@pytest.fixture
|
||||
def large_png_image():
|
||||
"""Create a larger test PNG image for DCT mode."""
|
||||
img = Image.new('RGB', (400, 400), color='blue')
|
||||
img = Image.new("RGB", (400, 400), color="blue")
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format='PNG')
|
||||
img.save(buf, format="PNG")
|
||||
buf.seek(0)
|
||||
return buf.getvalue()
|
||||
|
||||
@@ -60,9 +61,9 @@ def large_png_image():
|
||||
@pytest.fixture
|
||||
def bmp_image():
|
||||
"""Create a test BMP image."""
|
||||
img = Image.new('RGB', (100, 100), color='blue')
|
||||
img = Image.new("RGB", (100, 100), color="blue")
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format='BMP')
|
||||
img.save(buf, format="BMP")
|
||||
buf.seek(0)
|
||||
return buf.getvalue()
|
||||
|
||||
@@ -70,9 +71,9 @@ def bmp_image():
|
||||
@pytest.fixture
|
||||
def jpeg_image():
|
||||
"""Create a test JPEG image."""
|
||||
img = Image.new('RGB', (100, 100), color='green')
|
||||
img = Image.new("RGB", (100, 100), color="green")
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format='JPEG')
|
||||
img.save(buf, format="JPEG")
|
||||
buf.seek(0)
|
||||
return buf.getvalue()
|
||||
|
||||
@@ -80,9 +81,9 @@ def jpeg_image():
|
||||
@pytest.fixture
|
||||
def gif_image():
|
||||
"""Create a test GIF image."""
|
||||
img = Image.new('RGB', (100, 100), color='yellow')
|
||||
img = Image.new("RGB", (100, 100), color="yellow")
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format='GIF')
|
||||
img.save(buf, format="GIF")
|
||||
buf.seek(0)
|
||||
return buf.getvalue()
|
||||
|
||||
@@ -91,6 +92,7 @@ def gif_image():
|
||||
# Key Generation Tests (v3.2.0 Updated)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestKeygen:
|
||||
"""Tests for key generation functions."""
|
||||
|
||||
@@ -99,7 +101,7 @@ class TestKeygen:
|
||||
pin = generate_pin()
|
||||
assert len(pin) == 6
|
||||
assert pin.isdigit()
|
||||
assert pin[0] != '0'
|
||||
assert pin[0] != "0"
|
||||
|
||||
def test_generate_pin_lengths(self):
|
||||
"""PIN generation should work for all valid lengths."""
|
||||
@@ -129,7 +131,7 @@ class TestKeygen:
|
||||
# v3.2.0: Single passphrase instead of 7 daily phrases
|
||||
assert creds.passphrase is not None
|
||||
assert isinstance(creds.passphrase, str)
|
||||
assert ' ' in creds.passphrase # Should have multiple words
|
||||
assert " " in creds.passphrase # Should have multiple words
|
||||
|
||||
def test_generate_credentials_rsa_only(self):
|
||||
"""RSA-only credentials should have single passphrase."""
|
||||
@@ -180,6 +182,7 @@ class TestKeygen:
|
||||
# Validation Tests (v3.2.0 Updated)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestValidation:
|
||||
"""Tests for validation functions."""
|
||||
|
||||
@@ -250,56 +253,59 @@ class TestValidation:
|
||||
# Output Format Tests
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestOutputFormat:
|
||||
"""Tests for output format handling."""
|
||||
|
||||
def test_png_stays_png(self):
|
||||
"""PNG input should produce PNG output."""
|
||||
fmt, ext = get_output_format('PNG')
|
||||
assert fmt == 'PNG'
|
||||
assert ext == 'png'
|
||||
fmt, ext = get_output_format("PNG")
|
||||
assert fmt == "PNG"
|
||||
assert ext == "png"
|
||||
|
||||
def test_bmp_stays_bmp(self):
|
||||
"""BMP input should produce BMP output."""
|
||||
fmt, ext = get_output_format('BMP')
|
||||
assert fmt == 'BMP'
|
||||
assert ext == 'bmp'
|
||||
fmt, ext = get_output_format("BMP")
|
||||
assert fmt == "BMP"
|
||||
assert ext == "bmp"
|
||||
|
||||
def test_jpeg_becomes_png(self):
|
||||
"""JPEG input should produce PNG output (lossless)."""
|
||||
fmt, ext = get_output_format('JPEG')
|
||||
assert fmt == 'PNG'
|
||||
assert ext == 'png'
|
||||
fmt, ext = get_output_format("JPEG")
|
||||
assert fmt == "PNG"
|
||||
assert ext == "png"
|
||||
|
||||
def test_gif_becomes_png(self):
|
||||
"""GIF input should produce PNG output."""
|
||||
fmt, ext = get_output_format('GIF')
|
||||
assert fmt == 'PNG'
|
||||
assert ext == 'png'
|
||||
fmt, ext = get_output_format("GIF")
|
||||
assert fmt == "PNG"
|
||||
assert ext == "png"
|
||||
|
||||
def test_none_becomes_png(self):
|
||||
"""None format should default to PNG."""
|
||||
fmt, ext = get_output_format(None)
|
||||
assert fmt == 'PNG'
|
||||
assert ext == 'png'
|
||||
assert fmt == "PNG"
|
||||
assert ext == "png"
|
||||
|
||||
def test_unknown_becomes_png(self):
|
||||
"""Unknown format should default to PNG."""
|
||||
fmt, ext = get_output_format('UNKNOWN')
|
||||
assert fmt == 'PNG'
|
||||
assert ext == 'png'
|
||||
fmt, ext = get_output_format("UNKNOWN")
|
||||
assert fmt == "PNG"
|
||||
assert ext == "png"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Header Overhead Test (v4.0.0)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestConstants:
|
||||
"""Tests for constants and configuration."""
|
||||
|
||||
def test_header_overhead_value(self):
|
||||
"""Header overhead should be 66 bytes (v4.0.0: added flags byte)."""
|
||||
from stegasoo.steganography import HEADER_OVERHEAD
|
||||
|
||||
assert HEADER_OVERHEAD == 66
|
||||
|
||||
|
||||
@@ -307,6 +313,7 @@ class TestConstants:
|
||||
# Encode/Decode Tests (v4.0.0 Updated)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestEncodeDecode:
|
||||
"""Tests for encoding and decoding functions."""
|
||||
|
||||
@@ -322,19 +329,19 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
assert result.stego_image is not None
|
||||
assert len(result.stego_image) > 0
|
||||
assert result.filename.endswith('.png')
|
||||
assert result.filename.endswith(".png")
|
||||
|
||||
# v3.2.0: Use passphrase parameter, no date_str
|
||||
decoded = decode(
|
||||
stego_image=result.stego_image,
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
assert decoded.message == message
|
||||
@@ -350,7 +357,7 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
# decode_text returns string directly
|
||||
@@ -358,7 +365,7 @@ class TestEncodeDecode:
|
||||
stego_image=result.stego_image,
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
assert decoded_text == message
|
||||
@@ -370,9 +377,9 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
passphrase="test phrase here now",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
assert result.filename.endswith('.png')
|
||||
assert result.filename.endswith(".png")
|
||||
|
||||
def test_bmp_carrier_produces_bmp(self, bmp_image, png_image):
|
||||
"""BMP carrier should produce BMP output."""
|
||||
@@ -381,9 +388,9 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=bmp_image,
|
||||
passphrase="test phrase here now",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
assert result.filename.endswith('.bmp')
|
||||
assert result.filename.endswith(".bmp")
|
||||
|
||||
def test_jpeg_carrier_produces_png(self, jpeg_image, png_image):
|
||||
"""JPEG carrier should produce PNG output (lossless)."""
|
||||
@@ -392,9 +399,9 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=jpeg_image,
|
||||
passphrase="test phrase here now",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
assert result.filename.endswith('.png')
|
||||
assert result.filename.endswith(".png")
|
||||
|
||||
def test_bmp_roundtrip(self, bmp_image, png_image):
|
||||
"""Full encode/decode cycle with BMP should work."""
|
||||
@@ -407,15 +414,15 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=bmp_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
assert result.filename.endswith('.bmp')
|
||||
assert result.filename.endswith(".bmp")
|
||||
|
||||
decoded = decode(
|
||||
stego_image=result.stego_image,
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
assert decoded.message == message
|
||||
@@ -427,7 +434,7 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
passphrase="test phrase here now",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
|
||||
with pytest.raises((stegasoo.DecryptionError, stegasoo.ExtractionError)):
|
||||
@@ -435,7 +442,7 @@ class TestEncodeDecode:
|
||||
stego_image=result.stego_image,
|
||||
reference_photo=png_image,
|
||||
passphrase="test phrase here now",
|
||||
pin="654321" # Wrong PIN
|
||||
pin="654321", # Wrong PIN
|
||||
)
|
||||
|
||||
def test_wrong_passphrase_fails(self, png_image):
|
||||
@@ -445,7 +452,7 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
passphrase="correct phrase here now",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
|
||||
with pytest.raises((stegasoo.DecryptionError, stegasoo.ExtractionError)):
|
||||
@@ -453,7 +460,7 @@ class TestEncodeDecode:
|
||||
stego_image=result.stego_image,
|
||||
reference_photo=png_image,
|
||||
passphrase="wrong phrase here now", # Wrong passphrase
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
|
||||
def test_unicode_message(self, png_image):
|
||||
@@ -467,14 +474,14 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
decoded = decode(
|
||||
stego_image=result.stego_image,
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
assert decoded.message == message
|
||||
@@ -486,18 +493,20 @@ class TestEncodeDecode:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
passphrase="test phrase here now",
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
# Filename format: {random_hex}_{YYYYMMDD}.{ext}
|
||||
# e.g., "a1b2c3d4_20251227.png"
|
||||
import re
|
||||
assert re.search(r'^[a-f0-9]{8}_\d{8}\.png$', result.filename)
|
||||
|
||||
assert re.search(r"^[a-f0-9]{8}_\d{8}\.png$", result.filename)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# DCT Mode Tests (v3.2.0)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestDCTMode:
|
||||
"""Tests for DCT steganography mode."""
|
||||
|
||||
@@ -519,7 +528,7 @@ class TestDCTMode:
|
||||
carrier_image=large_png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
embed_mode='dct'
|
||||
embed_mode="dct",
|
||||
)
|
||||
|
||||
assert result.stego_image is not None
|
||||
@@ -528,7 +537,7 @@ class TestDCTMode:
|
||||
stego_image=result.stego_image,
|
||||
reference_photo=large_png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin
|
||||
pin=pin,
|
||||
)
|
||||
|
||||
assert decoded.message == message
|
||||
@@ -545,7 +554,7 @@ class TestDCTMode:
|
||||
carrier_image=large_png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
embed_mode='dct'
|
||||
embed_mode="dct",
|
||||
)
|
||||
|
||||
# Decode with auto mode (default)
|
||||
@@ -554,7 +563,7 @@ class TestDCTMode:
|
||||
reference_photo=large_png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
embed_mode='auto'
|
||||
embed_mode="auto",
|
||||
)
|
||||
|
||||
assert decoded.message == message
|
||||
@@ -564,19 +573,20 @@ class TestDCTMode:
|
||||
# Version Tests
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestVersion:
|
||||
"""Tests for version information."""
|
||||
|
||||
def test_version_exists(self):
|
||||
"""Version string should exist and be valid."""
|
||||
assert hasattr(stegasoo, '__version__')
|
||||
parts = stegasoo.__version__.split('.')
|
||||
assert hasattr(stegasoo, "__version__")
|
||||
parts = stegasoo.__version__.split(".")
|
||||
assert len(parts) >= 2
|
||||
assert all(p.isdigit() for p in parts[:2])
|
||||
|
||||
def test_version_is_4_0_0(self):
|
||||
"""Version should be 4.0.0 or higher."""
|
||||
parts = stegasoo.__version__.split('.')
|
||||
parts = stegasoo.__version__.split(".")
|
||||
major = int(parts[0])
|
||||
assert major >= 4
|
||||
|
||||
@@ -585,6 +595,7 @@ class TestVersion:
|
||||
# Backward Compatibility Tests
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestBackwardCompatibility:
|
||||
"""Tests for backward compatibility handling."""
|
||||
|
||||
@@ -596,7 +607,7 @@ class TestBackwardCompatibility:
|
||||
reference_photo=png_image,
|
||||
carrier_image=png_image,
|
||||
day_phrase="old style phrase", # Old parameter name
|
||||
pin="123456"
|
||||
pin="123456",
|
||||
)
|
||||
|
||||
def test_old_date_str_parameter_raises(self, png_image):
|
||||
@@ -608,7 +619,7 @@ class TestBackwardCompatibility:
|
||||
carrier_image=png_image,
|
||||
passphrase="test phrase here now",
|
||||
pin="123456",
|
||||
date_str="2025-01-01" # Removed parameter
|
||||
date_str="2025-01-01", # Removed parameter
|
||||
)
|
||||
|
||||
|
||||
@@ -616,6 +627,7 @@ class TestBackwardCompatibility:
|
||||
# Channel Key Tests (v4.0.0)
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestChannelKey:
|
||||
"""Tests for channel key functionality (v4.0.0)."""
|
||||
|
||||
@@ -624,7 +636,7 @@ class TestChannelKey:
|
||||
key = generate_channel_key()
|
||||
# Format: XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX (8 groups of 4)
|
||||
assert len(key) == 39
|
||||
parts = key.split('-')
|
||||
parts = key.split("-")
|
||||
assert len(parts) == 8
|
||||
for part in parts:
|
||||
assert len(part) == 4
|
||||
@@ -665,7 +677,7 @@ class TestChannelKey:
|
||||
carrier_image=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key=channel_key
|
||||
channel_key=channel_key,
|
||||
)
|
||||
|
||||
assert result.stego_image is not None
|
||||
@@ -676,7 +688,7 @@ class TestChannelKey:
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key=channel_key
|
||||
channel_key=channel_key,
|
||||
)
|
||||
|
||||
assert decoded.message == message
|
||||
@@ -696,7 +708,7 @@ class TestChannelKey:
|
||||
carrier_image=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key=channel_key1
|
||||
channel_key=channel_key1,
|
||||
)
|
||||
|
||||
# Decode with different channel key should fail
|
||||
@@ -706,7 +718,7 @@ class TestChannelKey:
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key=channel_key2
|
||||
channel_key=channel_key2,
|
||||
)
|
||||
|
||||
def test_encode_decode_public_mode(self, png_image):
|
||||
@@ -722,7 +734,7 @@ class TestChannelKey:
|
||||
carrier_image=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key="" # Explicit public mode
|
||||
channel_key="", # Explicit public mode
|
||||
)
|
||||
|
||||
# Decode without channel key
|
||||
@@ -731,7 +743,7 @@ class TestChannelKey:
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key="" # Explicit public mode
|
||||
channel_key="", # Explicit public mode
|
||||
)
|
||||
|
||||
assert decoded.message == message
|
||||
@@ -749,7 +761,7 @@ class TestChannelKey:
|
||||
carrier_image=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key="" # Public mode
|
||||
channel_key="", # Public mode
|
||||
)
|
||||
|
||||
# Decode with channel key should fail
|
||||
@@ -760,5 +772,5 @@ class TestChannelKey:
|
||||
reference_photo=png_image,
|
||||
passphrase=passphrase,
|
||||
pin=pin,
|
||||
channel_key=channel_key
|
||||
channel_key=channel_key,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user