1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: © 2004 Tristan Seligmann and Jonathan Jacobs
# SPDX-FileCopyrightText: © 2012 Bastian Kleineidam
# SPDX-FileCopyrightText: © 2015 Tobias Gruetzmacher
import json
import logging
import os
import re
import pytest
import responses
import dosagelib
import httpmocks
from dosagelib import cmd, output
def run_cmd(*options):
"""'Fake' run dosage with given options."""
retval = cmd.main(('--allow-multiple',) + options)
# Cleanup logging
root = logging.getLogger()
ourhandlers = (x for x in root.handlers if isinstance(x, output.RichHandler))
for handler in ourhandlers:
root.removeHandler(handler)
return retval
def cmd_ok(*options):
assert run_cmd(*options) == 0
def cmd_err(*options):
assert run_cmd(*options) == 1
@pytest.mark.usefixtures('_nosleep', '_noappdirs')
class TestDosage:
"""Test the dosage commandline client."""
# This shouldn't hit the network at all, so add responses without mocks to
# make sure it doesn't do that
@responses.activate
@pytest.mark.parametrize(('option'), [
('-l'),
('--list'),
('--singlelist'),
])
def test_list_comics(self, option, capfd):
cmd_ok(option)
out = capfd.readouterr().out
assert 'ADummyTestScraper' in out
@responses.activate
def test_display_version(self):
cmd_ok("--version")
@responses.activate
def test_update_available(self, capfd):
responses.add(responses.GET, re.compile(r'https://api\.github\.com/'),
json={'tag_name': '9999.0', 'assets': [
{'browser_download_url': 'TEST.whl'},
{'browser_download_url': 'TEST.exe'},
]})
cmd_ok('--version', '-v')
out = capfd.readouterr().out
best = 'TEST.exe' if os.name == 'nt' else 'TEST.whl'
assert best in out
assert 'A new version' in out
@responses.activate
def test_no_update_available(self, capfd):
responses.add(responses.GET, re.compile(r'https://api\.github\.com/'),
json={'tag_name': '1.0'})
cmd_ok('--version', '-v')
out = capfd.readouterr().out
assert 'Detected local or development' in out
@responses.activate
def test_current(self, capfd):
responses.add(responses.GET, re.compile(r'https://api\.github\.com/'),
json={'tag_name': dosagelib.__version__})
cmd_ok('--version', '-v')
out = capfd.readouterr().out
assert out.endswith('issues\n')
@responses.activate
def test_update_broken(self, capfd):
responses.add(responses.GET, re.compile(r'https://api\.github\.com/'),
json={})
cmd_ok('--version', '-v')
out = capfd.readouterr().out
assert 'KeyError' in out
@responses.activate
def test_update_rate_limit(self, capfd):
responses.add(responses.GET, re.compile(r'https://api\.github\.com/'),
status=403)
cmd_ok('--version', '-v')
out = capfd.readouterr().out
assert 'HTTPError' in out
def test_display_help(self):
for option in ("-h", "--help"):
with pytest.raises(SystemExit):
run_cmd(option)
def test_module_help(self, capfd):
cmd_ok("-m", "-t", "xkcd")
out = capfd.readouterr().out
assert re.match(r'([0-9][0-9]:){2}.. xkcd>', out)
def test_broken_basepath_removal(self):
assert run_cmd('-m', 'Comicsxkcd') == 2
def test_working_basepath_removal(self):
cmd_ok('-m', 'Comics/xkcd')
cmd_ok('-m', 'Comics\\xkcd')
def test_no_comics_specified(self):
cmd_err()
def test_unknown_option(self):
with pytest.raises(SystemExit):
run_cmd('--imadoofus')
def test_multiple_comics_match(self):
cmd_err('Garfield')
@responses.activate
def test_fetch_html_and_rss_json(self, tmpdir):
httpmocks.xkcd()
cmd_ok("-n", "2", "-v", "-b", str(tmpdir), "-o", "html", "-o", "rss",
"-o", "json", "--no-downscale", "xkcd")
@responses.activate
def test_fetch_html_and_rss_2(self, tmp_path):
httpmocks.page('https://www.bloomingfaeries.com/', 'bf-home')
httpmocks.page(re.compile('.*/comic/601.*'), 'bf-601')
httpmocks.png(re.compile(r'https://i0\.wp.*/BF601.*jpg'))
httpmocks.png(re.compile(r'https://i0\.wp.*/BF602.*jpg'), 'tall')
cmd_ok("--numstrips", "2", "--baseurl", "bla", "--basepath",
str(tmp_path), "--output", "rss", "--output", "html", "--adult",
"BloomingFaeries")
html = next((tmp_path / 'html').glob('*.html')).read_text()
assert "width=" in html
@responses.activate
def test_fetch_html_broken_img(self, tmp_path):
httpmocks.page('https://www.bloomingfaeries.com/', 'bf-home')
httpmocks.page(re.compile('.*/comic/601.*'), 'bf-601')
responses.add(responses.GET, re.compile(r'.*\.jpg'), body=b'\377\330',
content_type='image/jpeg')
cmd_ok("--numstrips", "2", "--baseurl", "bla", "--basepath",
str(tmp_path), "--output", "html", "--adult", "BloomingFaeries")
html = next((tmp_path / 'html').glob('*.html')).read_text()
assert "width=" not in html
@responses.activate
def test_fetch_indexed(self, tmpdir):
httpmocks.xkcd()
cmd_ok("-n", "2", "-v", "-b", str(tmpdir), "xkcd:303")
@responses.activate
def test_fetch_all_existing(self, tmp_path):
httpmocks.xkcd()
xkcd = tmp_path / 'xkcd'
xkcd.mkdir()
other = tmp_path / 'randomdir'
other.mkdir()
cmd_ok('-v', '-b', str(tmp_path), '@')
assert len(list(xkcd.glob('*'))) == 2
assert len(list(other.glob('*'))) == 0
@responses.activate
def test_json_page_key_bounce_and_multi_image(self, tmpdir):
httpmocks.page(re.compile(r'.*com/$'), 'zp-home')
httpmocks.page(re.compile(r'.*com/comic/missing/$'), 'zp-223')
httpmocks.page(re.compile(r'.*com/comic/lifejacket/$'), 'zp-222')
httpmocks.jpeg(re.compile(r'https://cdn-.*\.jpg'))
cmd_ok("-v", "-b", str(tmpdir), "-o", "json", "ZenPencils")
directory = tmpdir.join('ZenPencils')
f = directory.join('dosage.json').open(encoding='utf-8')
data = json.load(f)
f.close()
pages = data['pages']
assert len(pages) == 1
page = list(pages.keys())[0]
assert page == 'https://zenpencils.com/comic/missing/'
images = data['pages'][page]['images']
assert len(images) == 2
for imgfile in images.values():
assert directory.join(imgfile).check(file=1)
|