1from typing import List
2from typing import Union
3
4import pytest
5
6
7class TestPasteCapture:
8    @pytest.fixture
9    def pastebinlist(self, monkeypatch, request) -> List[Union[str, bytes]]:
10        pastebinlist = []  # type: List[Union[str, bytes]]
11        plugin = request.config.pluginmanager.getplugin("pastebin")
12        monkeypatch.setattr(plugin, "create_new_paste", pastebinlist.append)
13        return pastebinlist
14
15    def test_failed(self, testdir, pastebinlist):
16        testpath = testdir.makepyfile(
17            """
18            import pytest
19            def test_pass():
20                pass
21            def test_fail():
22                assert 0
23            def test_skip():
24                pytest.skip("")
25        """
26        )
27        reprec = testdir.inline_run(testpath, "--pastebin=failed")
28        assert len(pastebinlist) == 1
29        s = pastebinlist[0]
30        assert s.find("def test_fail") != -1
31        assert reprec.countoutcomes() == [1, 1, 1]
32
33    def test_all(self, testdir, pastebinlist):
34        from _pytest.pytester import LineMatcher
35
36        testpath = testdir.makepyfile(
37            """
38            import pytest
39            def test_pass():
40                pass
41            def test_fail():
42                assert 0
43            def test_skip():
44                pytest.skip("")
45        """
46        )
47        reprec = testdir.inline_run(testpath, "--pastebin=all", "-v")
48        assert reprec.countoutcomes() == [1, 1, 1]
49        assert len(pastebinlist) == 1
50        contents = pastebinlist[0].decode("utf-8")
51        matcher = LineMatcher(contents.splitlines())
52        matcher.fnmatch_lines(
53            [
54                "*test_pass PASSED*",
55                "*test_fail FAILED*",
56                "*test_skip SKIPPED*",
57                "*== 1 failed, 1 passed, 1 skipped in *",
58            ]
59        )
60
61    def test_non_ascii_paste_text(self, testdir, pastebinlist):
62        """Make sure that text which contains non-ascii characters is pasted
63        correctly. See #1219.
64        """
65        testdir.makepyfile(
66            test_unicode="""\
67            def test():
68                assert '☺' == 1
69            """
70        )
71        result = testdir.runpytest("--pastebin=all")
72        expected_msg = "*assert '☺' == 1*"
73        result.stdout.fnmatch_lines(
74            [
75                expected_msg,
76                "*== 1 failed in *",
77                "*Sending information to Paste Service*",
78            ]
79        )
80        assert len(pastebinlist) == 1
81
82
83class TestPaste:
84    @pytest.fixture
85    def pastebin(self, request):
86        return request.config.pluginmanager.getplugin("pastebin")
87
88    @pytest.fixture
89    def mocked_urlopen_fail(self, monkeypatch):
90        """Monkeypatch the actual urlopen call to emulate a HTTP Error 400."""
91        calls = []
92
93        import urllib.error
94        import urllib.request
95
96        def mocked(url, data):
97            calls.append((url, data))
98            raise urllib.error.HTTPError(url, 400, "Bad request", None, None)
99
100        monkeypatch.setattr(urllib.request, "urlopen", mocked)
101        return calls
102
103    @pytest.fixture
104    def mocked_urlopen_invalid(self, monkeypatch):
105        """Monkeypatch the actual urlopen calls done by the internal plugin
106        function that connects to bpaste service, but return a url in an
107        unexpected format."""
108        calls = []
109
110        def mocked(url, data):
111            calls.append((url, data))
112
113            class DummyFile:
114                def read(self):
115                    # part of html of a normal response
116                    return b'View <a href="/invalid/3c0c6750bd">raw</a>.'
117
118            return DummyFile()
119
120        import urllib.request
121
122        monkeypatch.setattr(urllib.request, "urlopen", mocked)
123        return calls
124
125    @pytest.fixture
126    def mocked_urlopen(self, monkeypatch):
127        """Monkeypatch the actual urlopen calls done by the internal plugin
128        function that connects to bpaste service."""
129        calls = []
130
131        def mocked(url, data):
132            calls.append((url, data))
133
134            class DummyFile:
135                def read(self):
136                    # part of html of a normal response
137                    return b'View <a href="/raw/3c0c6750bd">raw</a>.'
138
139            return DummyFile()
140
141        import urllib.request
142
143        monkeypatch.setattr(urllib.request, "urlopen", mocked)
144        return calls
145
146    def test_pastebin_invalid_url(self, pastebin, mocked_urlopen_invalid):
147        result = pastebin.create_new_paste(b"full-paste-contents")
148        assert (
149            result
150            == "bad response: invalid format ('View <a href=\"/invalid/3c0c6750bd\">raw</a>.')"
151        )
152        assert len(mocked_urlopen_invalid) == 1
153
154    def test_pastebin_http_error(self, pastebin, mocked_urlopen_fail):
155        result = pastebin.create_new_paste(b"full-paste-contents")
156        assert result == "bad response: HTTP Error 400: Bad request"
157        assert len(mocked_urlopen_fail) == 1
158
159    def test_create_new_paste(self, pastebin, mocked_urlopen):
160        result = pastebin.create_new_paste(b"full-paste-contents")
161        assert result == "https://bpaste.net/show/3c0c6750bd"
162        assert len(mocked_urlopen) == 1
163        url, data = mocked_urlopen[0]
164        assert type(data) is bytes
165        lexer = "text"
166        assert url == "https://bpaste.net"
167        assert "lexer=%s" % lexer in data.decode()
168        assert "code=full-paste-contents" in data.decode()
169        assert "expiry=1week" in data.decode()
170
171    def test_create_new_paste_failure(self, pastebin, monkeypatch):
172        import io
173        import urllib.request
174
175        def response(url, data):
176            stream = io.BytesIO(b"something bad occurred")
177            return stream
178
179        monkeypatch.setattr(urllib.request, "urlopen", response)
180        result = pastebin.create_new_paste(b"full-paste-contents")
181        assert result == "bad response: invalid format ('something bad occurred')"
182