test_assertion.py


Overview

`test_assertion.py` is a comprehensive test suite for the assertion rewriting and detailed assertion failure reporting mechanisms in the `pytest` testing framework. The primary focus of this file is to verify and validate how `pytest` processes and formats assertion failures, including complex comparisons, assertion rewriting hooks, and integration with plugins and various Python data structures.

This file contains numerous test classes and functions that:

The file uses the `pytest` testing framework and its utilities extensively for setup, test execution, and validation of outputs.


Detailed Explanation of Key Components

Functions

mock_config(verbose: int = 0, assertion_override: int | None = None) -> Config

Creates a mock configuration object mimicking a `pytest` `Config` instance, primarily for controlling verbosity settings during tests.

callop(op: str, left: Any, right: Any, verbose: int = 0) -> list[str] | None

Helper function to call `pytest_assertrepr_compare` with the given operator and operands, returning the assertion explanation lines.

callequal(left: Any, right: Any, verbose: int = 0) -> list[str] | None

Convenience wrapper for `callop` with the `"=="` operator.


Classes and Test Suites

The file defines multiple `Test*` classes, each grouping related tests. These are `pytest` test classes (not traditional classes with complex state), using test methods with assert statements and `pytest` fixtures.


TestMockConfig

Tests behavior of the `mock_config` function, verifying correct verbosity retrieval and error raising for unsupported verbosity types.


TestImportHookInstallation

Tests the installation and effect of assertion rewriting import hooks in various scenarios:

Key scenarios tested include:


TestBinReprIntegration

Tests that the `pytest_assertrepr_compare` hook is correctly called and integrated, including capturing values passed in the hook.


TestAssert_reprcompare

Extensive tests for the `pytest_assertrepr_compare` hook and its output on comparing various data types:

These tests validate that detailed diffs and explanations are generated accurately and robustly for assertion errors.


TestAssert_reprcompare_dataclass

Tests assertion comparison explanations specifically for Python `dataclasses`, including recursive dataclasses and verbosity levels.


TestAssert_reprcompare_attrsclass

Similar to dataclass tests but for the `attrs` library.


TestAssert_reprcompare_namedtuple

Tests comparisons of Python `NamedTuple` instances and the generated diff explanations.


TestFormatExplanation

Tests the formatting logic for assertion failure explanations, including:


TestTruncateExplanation

Tests the truncation logic applied to long assertion failure explanations to keep output manageable.


TestSetAssertions

Tests set-specific assertion comparisons and explanations:


Standalone Tests

The file also contains numerous standalone test functions verifying:


Important Implementation Details and Algorithms


Interaction With Other System Components


Usage Examples

These are mostly covered by the test methods themselves, for example:

def test_text_diff(self):
    assert callequal("spam", "eggs") == [
        "'spam' == 'eggs'",
        "",
        "- eggs",
        "+ spam",
    ]

This tests that when comparing two strings `"spam"` and `"eggs"`, the assertion explanation includes a line-by-line diff of the text.


Mermaid Diagram: Class Diagram of Key Test Classes

classDiagram
    class TestMockConfig {
        +test_verbose_exposes_value()
        +test_get_assertion_override_not_set_verbose_value()
        +test_get_assertion_override_set_custom_value()
        +test_get_unsupported_type_error()
    }

    class TestImportHookInstallation {
        +test_conftest_assertion_rewrite(pytester, initial_conftest, mode)
        +test_rewrite_assertions_pytester_plugin(pytester)
        +test_pytest_plugins_rewrite(pytester, mode)
        +test_pytest_plugins_rewrite_module_names(pytester, mode)
        +test_pytest_plugins_rewrite_module_names_correctly(pytester)
        +test_installed_plugin_rewrite(pytester, mode, monkeypatch, disable_plugin_autoload, explicit_specify)
        +test_rewrite_ast(pytester)
        +test_register_assert_rewrite_checks_types()
    }

    class TestAssert_reprcompare {
        +test_different_types()
        +test_summary()
        +test_text_diff()
        +test_bytes_diff_normal()
        +test_list()
        +test_iterable_full_diff(left, right, expected)
        +test_dict_wrap()
        +test_list_wrap_for_multiple_lines()
        +test_list_dont_wrap_strings()
        +test_dict()
        +test_dict_omitting()
        +test_repr_no_exc()
        +test_unicode()
        +test_nonascii_text()
        +test_format_nonascii_explanation()
        +test_nfc_nfd_same_string()
    }

    class TestAssert_reprcompare_dataclass {
        +test_dataclasses(pytester)
        +test_recursive_dataclasses(pytester)
        +test_recursive_dataclasses_verbose(pytester)
        +test_dataclasses_verbose(pytester)
        +test_dataclasses_with_attribute_comparison_off(pytester)
    }

    class TestAssert_reprcompare_attrsclass {
        +test_attrs()
        +test_attrs_recursive()
        +test_attrs_recursive_verbose()
        +test_attrs_verbose()
        +test_attrs_with_attribute_comparison_off()
        +test_comparing_two_different_attrs_classes()
        +test_attrs_with_custom_eq()
    }

    class TestAssert_reprcompare_namedtuple {
        +test_namedtuple()
        +test_comparing_two_different_namedtuple()
    }

    class TestFormatExplanation {
        +test_special_chars_full(pytester)
        +test_fmt_simple()
        +test_fmt_where()
        +test_fmt_and()
        +test_fmt_where_nested()
        +test_fmt_newline()
        +test_fmt_newline_escaped()
        +test_fmt_newline_before_where()
        +test_fmt_multi_newline_before_where()
    }

    class TestTruncateExplanation {
        +test_doesnt_truncate_when_input_is_empty_list()
        +test_truncates_at_8_lines_when_given_list_of_empty_strings()
        +test_truncates_at_8_lines_when_first_8_lines_are_LT_max_chars()
        +test_full_output_truncated(monkeypatch, pytester)
        +test_truncation_with_ini(monkeypatch, pytester, truncation_lines, truncation_chars, expected_lines_hidden)
    }

    class TestSetAssertions {
        +test_set_extra_item(op, pytester)
        +test_set_proper_superset_equal(pytester, op)
        +test_pytest_assertrepr_compare_integration(pytester)
    }

    TestImportHookInstallation --|> TestMockConfig
    TestAssert_reprcompare --|> TestMockConfig
    TestAssert_reprcompare_dataclass --|> TestAssert_reprcompare
    TestAssert_reprcompare_attrsclass --|> TestAssert_reprcompare
    TestAssert_reprcompare_namedtuple --|> TestAssert_reprcompare

Summary

`test_assertion.py` is a crucial part of the `pytest` internal test suite that ensures the robustness, correctness, and user-friendly reporting of assertion failures enhanced by `pytest`'s assertion rewriting mechanism. It covers a wide spectrum of use cases, data types, and edge cases, providing confidence in the behavior and output of assertion-related features in `pytest`.

The file is primarily a large collection of test cases with helper functions, focusing on exercising the assertion comparison logic, formatting, and integration with plugin and configuration systems of `pytest`. It helps guarantee that assertion failures are reported in a clear, detailed, and actionable manner to end users running tests with `pytest`.


End of Documentation for test_assertion.py