1"""
2Tests and examples for correct "+/-" usage in error diffs.
3
4See https://github.com/pytest-dev/pytest/issues/3333 for details.
5
6"""
7import sys
8
9import pytest
10
11
12TESTCASES = [
13    pytest.param(
14        """
15        def test_this():
16            result =   [1, 4, 3]
17            expected = [1, 2, 3]
18            assert result == expected
19        """,
20        """
21        >       assert result == expected
22        E       assert [1, 4, 3] == [1, 2, 3]
23        E         At index 1 diff: 4 != 2
24        E         Full diff:
25        E         - [1, 2, 3]
26        E         ?     ^
27        E         + [1, 4, 3]
28        E         ?     ^
29        """,
30        id="Compare lists, one item differs",
31    ),
32    pytest.param(
33        """
34        def test_this():
35            result =   [1, 2, 3]
36            expected = [1, 2]
37            assert result == expected
38        """,
39        """
40        >       assert result == expected
41        E       assert [1, 2, 3] == [1, 2]
42        E         Left contains one more item: 3
43        E         Full diff:
44        E         - [1, 2]
45        E         + [1, 2, 3]
46        E         ?      +++
47        """,
48        id="Compare lists, one extra item",
49    ),
50    pytest.param(
51        """
52        def test_this():
53            result =   [1, 3]
54            expected = [1, 2, 3]
55            assert result == expected
56        """,
57        """
58        >       assert result == expected
59        E       assert [1, 3] == [1, 2, 3]
60        E         At index 1 diff: 3 != 2
61        E         Right contains one more item: 3
62        E         Full diff:
63        E         - [1, 2, 3]
64        E         ?     ---
65        E         + [1, 3]
66        """,
67        id="Compare lists, one item missing",
68    ),
69    pytest.param(
70        """
71        def test_this():
72            result =   (1, 4, 3)
73            expected = (1, 2, 3)
74            assert result == expected
75        """,
76        """
77        >       assert result == expected
78        E       assert (1, 4, 3) == (1, 2, 3)
79        E         At index 1 diff: 4 != 2
80        E         Full diff:
81        E         - (1, 2, 3)
82        E         ?     ^
83        E         + (1, 4, 3)
84        E         ?     ^
85        """,
86        id="Compare tuples",
87    ),
88    pytest.param(
89        """
90        def test_this():
91            result =   {1, 3, 4}
92            expected = {1, 2, 3}
93            assert result == expected
94        """,
95        """
96        >       assert result == expected
97        E       assert {1, 3, 4} == {1, 2, 3}
98        E         Extra items in the left set:
99        E         4
100        E         Extra items in the right set:
101        E         2
102        E         Full diff:
103        E         - {1, 2, 3}
104        E         ?     ^  ^
105        E         + {1, 3, 4}
106        E         ?     ^  ^
107        """,
108        id="Compare sets",
109    ),
110    pytest.param(
111        """
112        def test_this():
113            result =   {1: 'spam', 3: 'eggs'}
114            expected = {1: 'spam', 2: 'eggs'}
115            assert result == expected
116        """,
117        """
118        >       assert result == expected
119        E       AssertionError: assert {1: 'spam', 3: 'eggs'} == {1: 'spam', 2: 'eggs'}
120        E         Common items:
121        E         {1: 'spam'}
122        E         Left contains 1 more item:
123        E         {3: 'eggs'}
124        E         Right contains 1 more item:
125        E         {2: 'eggs'}
126        E         Full diff:
127        E         - {1: 'spam', 2: 'eggs'}
128        E         ?             ^
129        E         + {1: 'spam', 3: 'eggs'}
130        E         ?             ^
131        """,
132        id="Compare dicts with differing keys",
133    ),
134    pytest.param(
135        """
136        def test_this():
137            result =   {1: 'spam', 2: 'eggs'}
138            expected = {1: 'spam', 2: 'bacon'}
139            assert result == expected
140        """,
141        """
142        >       assert result == expected
143        E       AssertionError: assert {1: 'spam', 2: 'eggs'} == {1: 'spam', 2: 'bacon'}
144        E         Common items:
145        E         {1: 'spam'}
146        E         Differing items:
147        E         {2: 'eggs'} != {2: 'bacon'}
148        E         Full diff:
149        E         - {1: 'spam', 2: 'bacon'}
150        E         ?                 ^^^^^
151        E         + {1: 'spam', 2: 'eggs'}
152        E         ?                 ^^^^
153        """,
154        id="Compare dicts with differing values",
155    ),
156    pytest.param(
157        """
158        def test_this():
159            result =   {1: 'spam', 2: 'eggs'}
160            expected = {1: 'spam', 3: 'bacon'}
161            assert result == expected
162        """,
163        """
164        >       assert result == expected
165        E       AssertionError: assert {1: 'spam', 2: 'eggs'} == {1: 'spam', 3: 'bacon'}
166        E         Common items:
167        E         {1: 'spam'}
168        E         Left contains 1 more item:
169        E         {2: 'eggs'}
170        E         Right contains 1 more item:
171        E         {3: 'bacon'}
172        E         Full diff:
173        E         - {1: 'spam', 3: 'bacon'}
174        E         ?             ^   ^^^^^
175        E         + {1: 'spam', 2: 'eggs'}
176        E         ?             ^   ^^^^
177        """,
178        id="Compare dicts with differing items",
179    ),
180    pytest.param(
181        """
182        def test_this():
183            result =   "spmaeggs"
184            expected = "spameggs"
185            assert result == expected
186        """,
187        """
188        >       assert result == expected
189        E       AssertionError: assert 'spmaeggs' == 'spameggs'
190        E         - spameggs
191        E         ?    -
192        E         + spmaeggs
193        E         ?   +
194        """,
195        id="Compare strings",
196    ),
197    pytest.param(
198        """
199        def test_this():
200            result =   "spam bacon eggs"
201            assert "bacon" not in result
202        """,
203        """
204        >       assert "bacon" not in result
205        E       AssertionError: assert 'bacon' not in 'spam bacon eggs'
206        E         'bacon' is contained here:
207        E           spam bacon eggs
208        E         ?      +++++
209        """,
210        id='Test "not in" string',
211    ),
212]
213if sys.version_info[:2] >= (3, 7):
214    TESTCASES.extend(
215        [
216            pytest.param(
217                """
218                from dataclasses import dataclass
219
220                @dataclass
221                class A:
222                    a: int
223                    b: str
224
225                def test_this():
226                    result =   A(1, 'spam')
227                    expected = A(2, 'spam')
228                    assert result == expected
229                """,
230                """
231                >       assert result == expected
232                E       AssertionError: assert A(a=1, b='spam') == A(a=2, b='spam')
233                E         Matching attributes:
234                E         ['b']
235                E         Differing attributes:
236                E         ['a']
237                E         Drill down into differing attribute a:
238                E           a: 1 != 2
239                E           +1
240                E           -2
241                """,
242                id="Compare data classes",
243            ),
244            pytest.param(
245                """
246                import attr
247
248                @attr.s(auto_attribs=True)
249                class A:
250                    a: int
251                    b: str
252
253                def test_this():
254                    result =   A(1, 'spam')
255                    expected = A(1, 'eggs')
256                    assert result == expected
257                """,
258                """
259                >       assert result == expected
260                E       AssertionError: assert A(a=1, b='spam') == A(a=1, b='eggs')
261                E         Matching attributes:
262                E         ['a']
263                E         Differing attributes:
264                E         ['b']
265                E         Drill down into differing attribute b:
266                E           b: 'spam' != 'eggs'
267                E           - eggs
268                E           + spam
269                """,
270                id="Compare attrs classes",
271            ),
272        ]
273    )
274
275
276@pytest.mark.parametrize("code, expected", TESTCASES)
277def test_error_diff(code, expected, testdir):
278    expected = [line.lstrip() for line in expected.splitlines()]
279    p = testdir.makepyfile(code)
280    result = testdir.runpytest(p, "-vv")
281    result.stdout.fnmatch_lines(expected)
282    assert result.ret == 1
283