| 
5 | 5 | from pathlib import Path  | 
6 | 6 | from pathlib import PurePath  | 
7 | 7 | import pprint  | 
 | 8 | +import re  | 
8 | 9 | import shutil  | 
9 | 10 | import sys  | 
10 | 11 | import tempfile  | 
@@ -2702,3 +2703,98 @@ def test_1(): pass  | 
2702 | 2703 |             ],  | 
2703 | 2704 |             consecutive=True,  | 
2704 | 2705 |         )  | 
 | 2706 | + | 
 | 2707 | + | 
 | 2708 | +class TestRequireUniqueParamsetIds:  | 
 | 2709 | +    CASES = [  | 
 | 2710 | +        ("[(1, 1), (1, 1)]", {"1-1": [0, 1]}),  | 
 | 2711 | +        ("[(1, 1), (1, 2), (1, 1)]", {"1-1": [0, 2]}),  | 
 | 2712 | +        ("[(1, 1), (2, 2), (1, 1)]", {"1-1": [0, 2]}),  | 
 | 2713 | +        ("[(1, 1), (2, 2), (1, 2), (2, 1), (1, 1)]", {"1-1": [0, 4]}),  | 
 | 2714 | +    ]  | 
 | 2715 | + | 
 | 2716 | +    @staticmethod  | 
 | 2717 | +    def _make_testfile(pytester: Pytester, parametrize_args: str) -> None:  | 
 | 2718 | +        pytester.makepyfile(  | 
 | 2719 | +            f"""  | 
 | 2720 | +            import pytest  | 
 | 2721 | +
  | 
 | 2722 | +            @pytest.mark.parametrize('y, x', {parametrize_args})  | 
 | 2723 | +            def test1(y, x):  | 
 | 2724 | +                pass  | 
 | 2725 | +            """  | 
 | 2726 | +        )  | 
 | 2727 | + | 
 | 2728 | +    @staticmethod  | 
 | 2729 | +    def _fnmatch_escape_repr(obj) -> str:  | 
 | 2730 | +        return re.sub(r"[*?[\]]", (lambda m: f"[{m.group()}]"), repr(obj))  | 
 | 2731 | + | 
 | 2732 | +    def _assert_duplicate_msg(self, result, expected_indices):  | 
 | 2733 | +        stream = result.stdout  | 
 | 2734 | +        stream.fnmatch_lines(  | 
 | 2735 | +            [  | 
 | 2736 | +                "When --require-unique-parameterization-ids set, pytest won't generate unique IDs for parameters.",  | 
 | 2737 | +                "test name: *::test1",  | 
 | 2738 | +                "argument names: [[]'y', 'x'[]]",  | 
 | 2739 | +                f"duplicates: {self._fnmatch_escape_repr(expected_indices)}",  | 
 | 2740 | +                "you must make sure all parameterization IDs are unique, either by:",  | 
 | 2741 | +                "- providing unique IDs per parameterization via the ids=[...] argument to @pytest.mark.parametrize",  | 
 | 2742 | +                "- providing a custom id function that generates unique IDs for each parameterization",  | 
 | 2743 | +                "- not setting --require-unique-parameterization-ids",  | 
 | 2744 | +            ]  | 
 | 2745 | +        )  | 
 | 2746 | +        assert result.ret != 0  | 
 | 2747 | + | 
 | 2748 | +    @pytest.mark.parametrize("parametrize_args, expected_indices", CASES)  | 
 | 2749 | +    def test_cli_enables(self, pytester: Pytester, parametrize_args, expected_indices):  | 
 | 2750 | +        pytester.makepyfile(  | 
 | 2751 | +            f"""  | 
 | 2752 | +            import pytest  | 
 | 2753 | +
  | 
 | 2754 | +            @pytest.mark.parametrize('y, x', {parametrize_args})  | 
 | 2755 | +            def test1(y, x):  | 
 | 2756 | +                pass  | 
 | 2757 | +            """  | 
 | 2758 | +        )  | 
 | 2759 | +        result = pytester.runpytest("--require-unique-parameterization-ids")  | 
 | 2760 | +        self._assert_duplicate_msg(result, expected_indices)  | 
 | 2761 | + | 
 | 2762 | +    @pytest.mark.parametrize("parametrize_args, expected_indices", CASES)  | 
 | 2763 | +    def test_ini_enables(self, pytester: Pytester, parametrize_args, expected_indices):  | 
 | 2764 | +        pytester.makeini(  | 
 | 2765 | +            """  | 
 | 2766 | +            [pytest]  | 
 | 2767 | +            require_unique_parameterization_ids = true  | 
 | 2768 | +            """  | 
 | 2769 | +        )  | 
 | 2770 | +        pytester.makepyfile(  | 
 | 2771 | +            f"""  | 
 | 2772 | +                    import pytest  | 
 | 2773 | +
  | 
 | 2774 | +                    @pytest.mark.parametrize('y, x', {parametrize_args})  | 
 | 2775 | +                    def test1(y, x):  | 
 | 2776 | +                        pass  | 
 | 2777 | +                    """  | 
 | 2778 | +        )  | 
 | 2779 | +        result = pytester.runpytest()  | 
 | 2780 | +        self._assert_duplicate_msg(result, expected_indices)  | 
 | 2781 | + | 
 | 2782 | +    def test_cli_overrides_ini_false(self, pytester: Pytester):  | 
 | 2783 | +        """CLI True should override ini False."""  | 
 | 2784 | +        pytester.makeini(  | 
 | 2785 | +            """  | 
 | 2786 | +            [pytest]  | 
 | 2787 | +            require_unique_parameterization_ids = false  | 
 | 2788 | +            """  | 
 | 2789 | +        )  | 
 | 2790 | +        pytester.makepyfile(  | 
 | 2791 | +            """  | 
 | 2792 | +            import pytest  | 
 | 2793 | +
  | 
 | 2794 | +            @pytest.mark.parametrize('y, x', [(1,1), (1,1)])  | 
 | 2795 | +            def test1(y, x):  | 
 | 2796 | +                pass  | 
 | 2797 | +            """  | 
 | 2798 | +        )  | 
 | 2799 | +        result = pytester.runpytest("--require-unique-parameterization-ids")  | 
 | 2800 | +        self._assert_duplicate_msg(result, {"1-1": [0, 1]})  | 
0 commit comments