def test_generate_exp_golomb_numbers_with_ascending_lengths(sign):
    for length, number in islice(
            generate_exp_golomb_with_ascending_lengths(sign),
            128,
    ):
        # Use a known-good implementation of a signed exp-golmb encoder and
        # check length is correct.
        f = BytesIO()
        w = BitstreamWriter(f)
        w.write_sint(number)
        actual_length = to_bit_offset(*w.tell())
        assert actual_length == length

        # Check sign of number
        if sign < 0:
            assert number <= 0
        else:
            assert number >= 0
    def test_happy_cases(self, block_bits, num_values, magnitude):
        value_sets = {
            dangle_type: generate_dangling_transform_values(
                block_bits,
                num_values,
                dangle_type,
                magnitude,
            )
            for dangle_type in DanglingTransformValueType
        }

        values_and_bits_beyond_ends = {}
        for description, values in value_sets.items():
            # Should all have required number of values
            assert len(values) == num_values

            # Should correctly encode into bounded block
            f = BytesIO()
            w = BitstreamWriter(f)
            w.bounded_block_begin(block_bits)
            for value in values:
                w.write_sint(value)

            # Should completely fill the block
            length_used = to_bit_offset(*w.tell())
            assert length_used == block_bits

            # Check we actually wrote 'beyond' the end of the block
            assert w.bits_remaining < 0

            # Work out which value and which bits actually first crossed the
            # end-of-block boundary (we'll later check that these actually
            # match our expectations later)
            w.flush()
            f.seek(0)
            r = BitstreamReader(f)
            r.bounded_block_begin(block_bits)
            value_beyond_end = None
            bits_beyond_end = None
            while r.bits_remaining >= 0:
                value_beyond_end = r.read_sint()
                bits_beyond_end = -r.bits_remaining
            values_and_bits_beyond_ends[description] = (
                value_beyond_end,
                bits_beyond_end,
            )

        # Check that the dangling value dangles in the expected way
        v, b = values_and_bits_beyond_ends[
            DanglingTransformValueType.zero_dangling]
        assert v == 0
        assert b == 1

        v, b = values_and_bits_beyond_ends[
            DanglingTransformValueType.sign_dangling]
        assert v != 0
        assert (-v).bit_length() == magnitude
        assert b == 1

        v, b = values_and_bits_beyond_ends[
            DanglingTransformValueType.stop_and_sign_dangling]
        assert v != 0
        assert (-v).bit_length() == magnitude
        assert b == 2

        v, b = values_and_bits_beyond_ends[
            DanglingTransformValueType.lsb_stop_and_sign_dangling]
        assert v != 0
        # NB: Larger due to exp-golmb code needing to end in 1
        assert (-v).bit_length() == magnitude + 1
        assert b == 3