Files

207 lines
6.0 KiB
Python

"""Tests for base64url module."""
import binascii
import pytest
import base64url
class TestEnc:
"""Tests for enc() function."""
def test_empty(self):
assert base64url.enc(b"") == ""
def test_single_byte(self):
assert base64url.enc(b"\x00") == "AA"
def test_no_padding_needed(self):
# 3 bytes encodes to 4 chars, no padding
assert base64url.enc(b"abc") == "YWJj"
def test_one_padding_stripped(self):
# 2 bytes encodes to 3 chars + 1 padding
assert base64url.enc(b"ab") == "YWI"
assert "=" not in base64url.enc(b"ab")
def test_two_padding_stripped(self):
# 1 byte encodes to 2 chars + 2 padding
assert base64url.enc(b"a") == "YQ"
assert "=" not in base64url.enc(b"a")
def test_urlsafe_chars(self):
# Bytes that produce + and / in standard Base64 should use - and _
# 0xfb -> standard: +, urlsafe: -
# 0xff -> standard: /, urlsafe: _
data = b"\xfb\xff\xfe"
result = base64url.enc(data)
assert "+" not in result
assert "/" not in result
assert "-" in result or "_" in result
def test_all_bytes(self):
# Verify all byte values encode/decode correctly
data = bytes(range(256))
encoded = base64url.enc(data)
assert "+" not in encoded
assert "/" not in encoded
assert "=" not in encoded
class TestDec:
"""Tests for dec() function."""
def test_empty(self):
assert base64url.dec("") == b""
def test_single_byte(self):
assert base64url.dec("AA") == b"\x00"
def test_without_padding(self):
assert base64url.dec("YWJj") == b"abc"
assert base64url.dec("YWI") == b"ab"
assert base64url.dec("YQ") == b"a"
def test_with_padding(self):
# Padding should be optional
assert base64url.dec("YWI=") == b"ab"
assert base64url.dec("YQ==") == b"a"
def test_urlsafe_chars(self):
# Should accept - instead of +, _ instead of /
assert base64url.dec("--__") == base64url.dec("++//")
def test_standard_base64_chars(self):
# Should also accept standard Base64 with + and /
assert base64url.dec("++//") == b"\xfb\xef\xff"
def test_mixed_chars(self):
# Mix of standard and urlsafe should work
assert base64url.dec("+-/_") is not None
def test_invalid_char_raises(self):
# Invalid characters should raise binascii.Error
with pytest.raises(binascii.Error):
base64url.dec("!!!!")
def test_invalid_char_in_middle_raises(self):
with pytest.raises(binascii.Error):
base64url.dec("YW!j")
def test_whitespace_raises(self):
# Whitespace should not be silently ignored
with pytest.raises(binascii.Error):
base64url.dec("YW Jj")
def test_newline_raises(self):
with pytest.raises(binascii.Error):
base64url.dec("YWJj\n")
class TestRoundtrip:
"""Tests for enc/dec roundtrip."""
def test_empty_roundtrip(self):
assert base64url.dec(base64url.enc(b"")) == b""
def test_hello_roundtrip(self):
assert base64url.dec(base64url.enc(b"hello")) == b"hello"
def test_binary_roundtrip(self):
data = bytes(range(256))
assert base64url.dec(base64url.enc(data)) == data
def test_various_lengths(self):
# Test lengths 0-20 to cover all padding scenarios
for i in range(21):
data = bytes(range(i))
assert base64url.dec(base64url.enc(data)) == data
def test_random_bytes(self):
import os
for _ in range(10):
data = os.urandom(100)
assert base64url.dec(base64url.enc(data)) == data
class TestEncLines:
"""Tests for enc_lines() function."""
def test_empty(self):
assert base64url.enc_lines(b"") == ""
def test_short_no_wrap(self):
# Short data fits on one line
result = base64url.enc_lines(b"hello", length=76)
assert "\n" not in result
assert result == "aGVsbG8"
def test_wrapping(self):
# 60 bytes -> 80 base64 chars, should wrap at 76
data = b"x" * 60
result = base64url.enc_lines(data, length=76)
lines = result.split("\n")
assert len(lines) == 2
assert len(lines[0]) == 76
assert len(lines[1]) == 4
def test_custom_line_length(self):
data = b"hello world"
result = base64url.enc_lines(data, length=4)
lines = result.split("\n")
assert all(len(line) <= 4 for line in lines)
def test_exact_multiple(self):
# 6 bytes -> 8 base64 chars, exactly 2 lines of 4
data = b"abcdef"
result = base64url.enc_lines(data, length=4)
lines = result.split("\n")
assert len(lines) == 2
assert all(len(line) == 4 for line in lines)
class TestDecLines:
"""Tests for dec_lines() function."""
def test_empty(self):
assert base64url.dec_lines("") == b""
def test_single_line(self):
assert base64url.dec_lines("aGVsbG8") == b"hello"
def test_multiline(self):
multiline = "aGVs\nbG8"
assert base64url.dec_lines(multiline) == b"hello"
def test_spaces(self):
spaced = "aGVs bG8"
assert base64url.dec_lines(spaced) == b"hello"
def test_tabs(self):
tabbed = "aGVs\tbG8"
assert base64url.dec_lines(tabbed) == b"hello"
def test_mixed_whitespace(self):
mixed = " aGVs\n\t bG8 \n"
assert base64url.dec_lines(mixed) == b"hello"
def test_crlf(self):
crlf = "aGVs\r\nbG8"
assert base64url.dec_lines(crlf) == b"hello"
class TestLinesRoundtrip:
"""Tests for enc_lines/dec_lines roundtrip."""
def test_roundtrip(self):
data = bytes(range(256))
assert base64url.dec_lines(base64url.enc_lines(data)) == data
def test_roundtrip_various_line_lengths(self):
data = b"hello world" * 10
for line_length in [4, 16, 64, 76, 100]:
encoded = base64url.enc_lines(data, length=line_length)
assert base64url.dec_lines(encoded) == data