# Path: sygnal/apnstruncate.py
# def json_encode(payload) -> bytes:
#     return json.dumps(payload, ensure_ascii=False).encode()
# 
# def truncate(payload: Dict[str, Any], max_length: int = 2048) -> Dict[str, Any]:
#     """
#     Truncate APNs fields to make the payload fit within the max length
#     specified.
#     Only truncates fields that are safe to do so.
# 
#     Args:
#         payload: nested dict that will be passed to APNs
#         max_length: Maximum length, in bytes, that the payload should occupy
#             when JSON-encoded.
# 
#     Returns:
#         Nested dict which should comply with the maximum length restriction.
# 
#     """
#     payload = payload.copy()
#     if "aps" not in payload:
#         if is_too_long(payload, max_length):
#             raise BodyTooLongException()
#         else:
#             return payload
#     aps = payload["aps"]
# 
#     # first ensure all our choppables are str objects.
#     # We need them to be for truncating to work and this
#     # makes more sense than checking every time.
#     for c in _choppables_for_aps(aps):
#         val = _choppable_get(aps, c)
#         if isinstance(val, bytes):
#             _choppable_put(aps, c, val.decode())
# 
#     # chop off whole unicode characters until it fits (or we run out of chars)
#     while is_too_long(payload, max_length):
#         longest = _longest_choppable(aps)
#         if longest is None:
#             raise BodyTooLongException()
# 
#         txt = _choppable_get(aps, longest)
#         # Note that python's support for this is actually broken on some OSes
#         # (see test_apnstruncate.py)
#         txt = txt[:-1]
#         _choppable_put(aps, longest, txt)
#         payload["aps"] = aps
# 
#     return payload


import string
import unittest
from sygnal.apnstruncate import json_encode, truncate
        aps = {"alert": {"body": txt}}
        self.assertEqual(
            txt[:5],
            truncate(payload_for_aps(aps), overhead + 5)["aps"]["alert"]["body"],
        )

    def test_truncate_loc_arg(self):
        """
        Tests that the 'alert' 'loc-args' field will be truncated when needed.
        (Tests with one loc arg)
        """
        overhead = len(json_encode(payload_for_aps({"alert": {"loc-args": [""]}})))
        txt = simplestring(10)
        aps = {"alert": {"loc-args": [txt]}}
        self.assertEqual(
            txt[:5],
            truncate(payload_for_aps(aps), overhead + 5)["aps"]["alert"]["loc-args"][0],
        )

    def test_truncate_loc_args(self):
        """
        Tests that the 'alert' 'loc-args' field will be truncated when needed.
        (Tests with two loc args)
        """
        overhead = len(json_encode(payload_for_aps({"alert": {"loc-args": ["", ""]}})))
        txt = simplestring(10)
        txt2 = simplestring(10, 3)
        aps = {"alert": {"loc-args": [txt, txt2]}}
        self.assertEqual(
            txt[:5],

# Path: sygnal/apnstruncate.py
# def json_encode(payload) -> bytes:
#     return json.dumps(payload, ensure_ascii=False).encode()
# 
# def truncate(payload: Dict[str, Any], max_length: int = 2048) -> Dict[str, Any]:
#     """
#     Truncate APNs fields to make the payload fit within the max length
#     specified.
#     Only truncates fields that are safe to do so.
# 
#     Args:
#         payload: nested dict that will be passed to APNs
#         max_length: Maximum length, in bytes, that the payload should occupy
#             when JSON-encoded.
# 
#     Returns:
#         Nested dict which should comply with the maximum length restriction.
# 
#     """
#     payload = payload.copy()
#     if "aps" not in payload:
#         if is_too_long(payload, max_length):
#             raise BodyTooLongException()
#         else:
#             return payload
#     aps = payload["aps"]
# 
#     # first ensure all our choppables are str objects.
#     # We need them to be for truncating to work and this
#     # makes more sense than checking every time.
#     for c in _choppables_for_aps(aps):
#         val = _choppable_get(aps, c)
#         if isinstance(val, bytes):
#             _choppable_put(aps, c, val.decode())
# 
#     # chop off whole unicode characters until it fits (or we run out of chars)
#     while is_too_long(payload, max_length):
#         longest = _longest_choppable(aps)
#         if longest is None:
#             raise BodyTooLongException()
# 
#         txt = _choppable_get(aps, longest)
#         # Note that python's support for this is actually broken on some OSes
#         # (see test_apnstruncate.py)
#         txt = txt[:-1]
#         _choppable_put(aps, longest, txt)
#         payload["aps"] = aps
# 
#     return payload


# Path: tests/test_apnstruncate.py
import string
import unittest
from sygnal.apnstruncate import json_encode, truncate

        aps = {"alert": {"body": txt}}
        self.assertEqual(
            txt[:5],
            truncate(payload_for_aps(aps), overhead + 5)["aps"]["alert"]["body"],
        )

    def test_truncate_loc_arg(self):
        """
        Tests that the 'alert' 'loc-args' field will be truncated when needed.
        (Tests with one loc arg)
        """
        overhead = len(json_encode(payload_for_aps({"alert": {"loc-args": [""]}})))
        txt = simplestring(10)
        aps = {"alert": {"loc-args": [txt]}}
        self.assertEqual(
            txt[:5],
            truncate(payload_for_aps(aps), overhead + 5)["aps"]["alert"]["loc-args"][0],
        )

    def test_truncate_loc_args(self):
        """
        Tests that the 'alert' 'loc-args' field will be truncated when needed.
        (Tests with two loc args)
        """
        overhead = len(json_encode(payload_for_aps({"alert": {"loc-args": ["", ""]}})))
        txt = simplestring(10)
        txt2 = simplestring(10, 3)
        aps = {"alert": {"loc-args": [txt, txt2]}}
        self.assertEqual(
            txt[:5],

            truncate(payload_for_aps(aps), overhead + 10)["aps"]["alert"]["loc-args"][