blob: bf8ea4590e5e3074e2d177a2ae1b4b83b0dc0fe3 [file] [log] [blame] [edit]
[case testAllBase64Features_librt_experimental]
from typing import Any
import base64
import binascii
import random
from librt.base64 import b64encode, b64decode, urlsafe_b64encode, urlsafe_b64decode
from testutil import assertRaises
rand_values = [random.randbytes(random.randint(1, 2000)) for _ in range(2000)]
def test_encode_basic() -> None:
assert b64encode(b"x") == b"eA=="
with assertRaises(TypeError):
b64encode(bytearray(b"x"))
def check_encode(b: bytes) -> None:
assert b64encode(b) == getattr(base64, "b64encode")(b)
def test_encode_different_strings() -> None:
for i in range(256):
check_encode(bytes([i]))
check_encode(bytes([i]) + b"x")
check_encode(bytes([i]) + b"xy")
check_encode(bytes([i]) + b"xyz")
check_encode(bytes([i]) + b"xyza")
check_encode(b"x" + bytes([i]))
check_encode(b"xy" + bytes([i]))
check_encode(b"xyz" + bytes([i]))
check_encode(b"xyza" + bytes([i]))
b = b"a\x00\xb7" * 1000
for i in range(1000):
check_encode(b[:i])
for b in b"", b"ab", b"bac", b"1234", b"xyz88", b"abc" * 200:
check_encode(b)
for b in rand_values:
check_encode(b)
def test_encode_wrappers() -> None:
funcs: list[Any] = [b64encode, urlsafe_b64encode]
for enc in funcs:
assert enc(b"x") == b"eA=="
with assertRaises(TypeError):
enc()
with assertRaises(TypeError):
enc(b"x", b"y")
def test_decode_basic() -> None:
assert b64decode(b"eA==") == b"x"
with assertRaises(TypeError):
b64decode(bytearray(b"eA=="))
for non_ascii in "\x80", "foo\u100bar", "foo\ua1234bar":
with assertRaises(ValueError):
b64decode(non_ascii)
def check_decode(b: bytes, encoded: bool = False) -> None:
if encoded:
enc = b
else:
enc = b64encode(b)
assert b64decode(enc) == getattr(base64, "b64decode")(enc)
if getattr(enc, "isascii")(): # Test stub has no "isascii"
enc_str = enc.decode("ascii")
assert b64decode(enc_str) == getattr(base64, "b64decode")(enc_str)
def test_decode_different_strings() -> None:
for i in range(256):
check_decode(bytes([i]))
check_decode(bytes([i]) + b"x")
check_decode(bytes([i]) + b"xy")
check_decode(bytes([i]) + b"xyz")
check_decode(bytes([i]) + b"xyza")
check_decode(b"x" + bytes([i]))
check_decode(b"xy" + bytes([i]))
check_decode(b"xyz" + bytes([i]))
check_decode(b"xyza" + bytes([i]))
b = b"a\x00\xb7" * 1000
for i in range(1000):
check_decode(b[:i])
for b in b"", b"ab", b"bac", b"1234", b"xyz88", b"abc" * 200:
check_decode(b)
for b in rand_values:
check_decode(b)
def is_base64_char(x: int) -> bool:
c = chr(x)
return ('a' <= c <= 'z') or ('A' <= c <= 'Z') or ('0' <= c <= '9') or c in '+/='
def test_decode_with_non_base64_chars() -> None:
# For stdlib compatibility, non-base64 characters should be ignored.
# Invalid characters as a suffix use a fast path.
check_decode(b"eA== ", encoded=True)
check_decode(b"eA==\n", encoded=True)
check_decode(b"eA== \t\n", encoded=True)
check_decode(b"\n", encoded=True)
check_decode(b" e A = = ", encoded=True)
# Special case: Two different encodings of the same data
check_decode(b"eAa=", encoded=True)
check_decode(b"eAY=", encoded=True)
for x in range(256):
if not is_base64_char(x):
b = bytes([x])
check_decode(b, encoded=True)
check_decode(b"eA==" + b, encoded=True)
check_decode(b"e" + b + b"A==", encoded=True)
check_decode(b"eA=" + b + b"=", encoded=True)
def check_decode_error(b: bytes, ignore_stdlib: bool = False) -> None:
if not ignore_stdlib:
with assertRaises(binascii.Error):
getattr(base64, "b64decode")(b)
# The raised error is different, since librt shouldn't depend on binascii
with assertRaises(ValueError):
b64decode(b)
def test_decode_with_invalid_padding() -> None:
check_decode_error(b"eA")
check_decode_error(b"eA=")
check_decode_error(b"eHk")
check_decode_error(b"eA = ")
# Here stdlib behavior seems nonsensical, so we don't try to duplicate it
check_decode_error(b"eA=a=", ignore_stdlib=True)
def test_decode_with_extra_data_after_padding() -> None:
check_decode(b"=", encoded=True)
check_decode(b"==", encoded=True)
check_decode(b"===", encoded=True)
check_decode(b"====", encoded=True)
check_decode(b"eA===", encoded=True)
check_decode(b"eHk==", encoded=True)
check_decode(b"eA==x", encoded=True)
check_decode(b"eHk=x", encoded=True)
check_decode(b"eA==abc=======efg", encoded=True)
def test_decode_wrappers() -> None:
funcs: list[Any] = [b64decode, urlsafe_b64decode]
for dec in funcs:
assert dec(b"eA==") == b"x"
with assertRaises(TypeError):
dec()
with assertRaises(TypeError):
dec(b"x", b"y")
def check_urlsafe_encode(b: bytes) -> None:
assert urlsafe_b64encode(b) == getattr(base64, "urlsafe_b64encode")(b)
def test_urlsafe_b64encode() -> None:
check_urlsafe_encode(b"")
check_urlsafe_encode(b"a")
check_urlsafe_encode(b"\xf8")
check_urlsafe_encode(b"\xfc")
check_urlsafe_encode(b"\xfcx")
check_urlsafe_encode(b"\xfcxy")
check_urlsafe_encode(b"\xfcxyz")
check_urlsafe_encode(bytes([x for x in range(256)]))
for b in rand_values:
check_urlsafe_encode(b)
def check_urlsafe_decode(b: bytes) -> None:
enc = urlsafe_b64encode(b)
assert urlsafe_b64decode(enc) == getattr(base64, "urlsafe_b64decode")(enc)
enc2 = b64encode(b)
assert urlsafe_b64decode(enc2) == getattr(base64, "urlsafe_b64decode")(enc2)
def test_urlsafe_b64decode() -> None:
# Don't test everything, since the implementation is mostly shared with b64decode.
check_urlsafe_decode(b"")
check_urlsafe_decode(b"a")
check_urlsafe_decode(b"\xf8")
check_urlsafe_decode(b"\xfc")
check_urlsafe_decode(b"\xfcx")
check_urlsafe_decode(b"\xfcxy")
check_urlsafe_decode(b"\xfcxyz")
check_urlsafe_decode(bytes([x for x in range(256)]))
for b in rand_values:
check_urlsafe_decode(b)
assert urlsafe_b64decode(b" e A = == !") == b"x"
def test_urlsafe_b64decode_errors() -> None:
for b in b"eA", b"eA=", b"eHk":
with assertRaises(ValueError):
b64decode(b)
[case testBase64FeaturesNotAvailableInNonExperimentalBuild_librt_base64]
# This also ensures librt.base64 can be built without experimental features
import librt.base64
def test_b64encode_not_available() -> None:
assert not hasattr(librt.base64, "b64encode")
[case testBase64UsedAtTopLevelOnly_librt_experimental]
from librt.base64 import b64encode
# The only reference to b64encode is at module top level
encoded = b64encode(b"x")
def test_top_level_only_encode() -> None:
assert encoded == b"eA=="