Repository: pytest-dev/pytest
File: src/_pytest/assertion/truncate.py (Python)

Code before:
    # The real value is
    # 64 (for the base message:
    # '...\n...Full output truncated (1 line hidden), use '-vv' to show")'
    # )
    # + 1 (for plural)
    # + int(math.log10(len(input_lines) - max_lines)) (number of hidden line, at least 1)
    # + 3 for the '...' added to the truncated line
    # But if there's more than 100 lines it's very likely that we're going to
    # truncate, so we don't need the exact value using log10.
    tolerable_max_chars = (
        max_chars + 70  # 64 + 1 (for plural) + 2 (for '99') + 3 for '...'
    )
    # The truncation explanation add two lines to the output
    tolerable_max_lines = max_lines + 2
    if (
        len(input_lines) <= tolerable_max_lines
        and input_char_count <= tolerable_max_chars
    ):
        return input_lines
    # Truncate first to max_lines, and then truncate to max_chars if necessary
    if max_lines > 0:
        truncated_explanation = input_lines[:max_lines]
    else:
        truncated_explanation = input_lines
    # We reevaluate the need to truncate chars following removal of some lines
    need_to_truncate_char = (
        70 < tolerable_max_chars < sum(len(e) for e in truncated_explanation)
    )
    if need_to_truncate_char:
        truncated_explanation = _truncate_by_char_count(
            truncated_explanation, max_chars
        )

    if truncated_explanation == input_lines:
        # No truncation happened, so we do not need to add any explanations
        return truncated_explanation

    truncated_explanation[-1] = truncated_explanation[-1] + "..."
    truncated_line_count = (
        len(input_lines) - len(truncated_explanation) + int(need_to_truncate_char)
    )
    return [
        *truncated_explanation,
        "",
        f"...Full output truncated ({truncated_line_count} line"
        f"{'' if truncated_line_count == 1 else 's'} hidden), {USAGE_MSG}",
    ]


def _truncate_by_char_count(input_lines: list[str], max_chars: int) -> list[str]:
    # Find point at which input length exceeds total allowed length

Review comment (bug):
If I understand correctly (tell me if I'm wrong), `max_lines == 0` means "don't truncate lines" and `max_chars == 0` means "don't truncate chars", right? I think then it would be more obvious to not do `70 < tolerable_max_chars` and instead do `max_chars > 0` for the "is chars truncation enabled?" check like before. It's equivalent but fits better with the `if max_lines > 0` check a few lines above it.

It will also be nice to document the meaning of `0`s in the docstring of the function, just so local reasoning about it is easier.

Code after:
    because _get_truncation_parameters was called first.
    """
    # The length of the truncation explanation depends on the number of lines
    # removed but is at least 68 characters:
    # The real value is
    # 64 (for the base message:
    # '...\n...Full output truncated (1 line hidden), use '-vv' to show")'
    # )
    # + 1 (for plural)
    # + int(math.log10(len(input_lines) - max_lines)) (number of hidden line, at least 1)
    # + 3 for the '...' added to the truncated line
    # But if there's more than 100 lines it's very likely that we're going to
    # truncate, so we don't need the exact value using log10.
    tolerable_max_chars = (
        max_chars + 70  # 64 + 1 (for plural) + 2 (for '99') + 3 for '...'
    )
    # The truncation explanation add two lines to the output
    if max_lines == 0 or len(input_lines) <= max_lines + 2:
        if max_chars == 0 or sum(len(s) for s in input_lines) <= tolerable_max_chars:
            return input_lines
        truncated_explanation = input_lines
    else:
        # Truncate first to max_lines, and then truncate to max_chars if necessary
        truncated_explanation = input_lines[:max_lines]
    # We reevaluate the need to truncate chars following removal of some lines
    need_to_truncate_char = (
        max_chars > 0
        and sum(len(e) for e in truncated_explanation) > tolerable_max_chars
    )
    if need_to_truncate_char:
        truncated_explanation = _truncate_by_char_count(
            truncated_explanation, max_chars
        )
    # Something was truncated, adding '...' at the end to show that
    truncated_explanation[-1] += "..."
    truncated_line_count = (
        len(input_lines) - len(truncated_explanation) + int(need_to_truncate_char)
    )
    return [
        *truncated_explanation,
        "",
        f"...Full output truncated ({truncated_line_count} line"
        f"{'' if truncated_line_count == 1 else 's'} hidden), {USAGE_MSG}",
    ]


def _truncate_by_char_count(input_lines: list[str], max_chars: int) -> list[str]:
    # Find point at which input length exceeds total allowed length
    iterated_char_count = 0
    for iterated_index, input_line in enumerate(input_lines):
        if iterated_char_count + len(input_line) > max_chars: