캡슐화 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

"""캡슐화의 헤더 오버헤드 비율 검증.

문서: 22.캡슐화 (정의의 길이 식, 카드 C1·C2)
정의: 층마다 헤더 h_l을 앞에 붙인다. 선에 실리는 길이 = M + sum(|h_l|).
주장: 헤더 크기가 고정이면 데이터가 작을수록 헤더 비율이 크다.
"""
from fractions import Fraction as F


def encapsulate(data, headers):
    """headers: 위층부터 아래층 순서의 헤더 이름. 반환: 아래층이 만든 메시지(리스트)."""
    msg = [data]
    for h in headers:
        msg = [h] + msg
    return msg


def decapsulate(msg, name):
    assert msg[0] == name
    return msg[1:]


def overhead(data_bytes, header_bytes):
    total = data_bytes + sum(header_bytes)
    return F(sum(header_bytes), total)


def main():
    # 카드 C1: RRP -> HHP
    wire = encapsulate("Data", ["RRP", "HHP"])
    assert wire == ["HHP", "RRP", "Data"]
    to_rrp = decapsulate(wire, "HHP")
    assert to_rrp == ["RRP", "Data"]
    assert decapsulate(to_rrp, "RRP") == ["Data"]
    print("[OK] 카드 C1: 망 [HHP|RRP|Data] -> RRP에 [RRP|Data] -> 응용에 [Data]")

    # 카드 C2: 세 층 20바이트씩
    a = overhead(40, [20, 20, 20])
    b = overhead(1_460, [20, 20, 20])
    assert a == F(3, 5)
    assert round(float(b) * 100, 1) == 3.9
    print(f"[OK] 카드 C2: 40바이트 -> {float(a):.0%}, 1,460바이트 -> {float(b):.1%}")

    # 주장: 데이터가 커질수록 비율이 줄어든다 (단조 감소)
    ratios = [overhead(d, [20, 20, 20]) for d in range(1, 3000)]
    assert all(x > y for x, y in zip(ratios, ratios[1:]))
    print("ALL CHECKS PASSED")


if __name__ == "__main__":
    main()