]>
Commit | Line | Data |
---|---|---|
1 | # paperdoorknob: Print glowfic | |
2 | # | |
3 | # This program is free software: you can redistribute it and/or modify it | |
4 | # under the terms of the GNU General Public License as published by the | |
5 | # Free Software Foundation, version 3. | |
6 | ||
7 | import dataclasses | |
8 | from io import BytesIO | |
9 | from sys import stderr | |
10 | import unittest | |
11 | ||
12 | from typing import Optional | |
13 | ||
14 | from fetch import FakeFetcher | |
15 | from images import FakeImageStore | |
16 | from glowfic import makeChunk, Thread | |
17 | from spec import Spec | |
18 | from texify import PandocTexifier | |
19 | ||
20 | ||
21 | def spec_for_testing(html: bytes, outbuf: Optional[BytesIO] = None) -> Spec: | |
22 | return Spec('https://fake/test', | |
23 | FakeFetcher({'https://fake/test': html, | |
24 | 'https://fake/test?view=flat': html}), | |
25 | FakeImageStore(), | |
26 | lambda x: x, | |
27 | lambda x: None, | |
28 | PandocTexifier('pandoc'), | |
29 | lambda x: x, | |
30 | 20, | |
31 | b'', | |
32 | None, | |
33 | stderr.buffer if outbuf is None else outbuf, | |
34 | lambda x: None) | |
35 | ||
36 | ||
37 | class TestSplit(unittest.TestCase): | |
38 | ||
39 | def testSplit1(self) -> None: | |
40 | t = Thread(spec_for_testing(b''' | |
41 | <html><body><div class="post-container post-post"> | |
42 | The "post" | |
43 | </div></body></html>''')) | |
44 | self.assertEqual([list(t.stripped_strings) for t in t.chunkDOMs()], | |
45 | [['The "post"']]) | |
46 | ||
47 | def testSplit2(self) -> None: | |
48 | t = Thread(spec_for_testing(b''' | |
49 | <html><body> | |
50 | <div class="post-container post-post">The "post"</div> | |
51 | <div class="flat-post-replies"> | |
52 | <div class="post-container post-reply">The "reply"</div> | |
53 | </div> | |
54 | </body></html>''')) | |
55 | self.assertEqual([list(t.stripped_strings) for t in t.chunkDOMs()], | |
56 | [['The "post"'], ['The "reply"']]) | |
57 | ||
58 | def testSplit3(self) -> None: | |
59 | t = Thread(spec_for_testing(b''' | |
60 | <html><body> | |
61 | <div class="post-container post-post">The "post"</div> | |
62 | <div class="flat-post-replies"> | |
63 | <div class="post-container post-reply">1st reply</div> | |
64 | <div class="post-container post-reply">2nd reply</div> | |
65 | </div> | |
66 | </body></html>''')) | |
67 | self.assertEqual([list(t.stripped_strings) for t in t.chunkDOMs()], | |
68 | [['The "post"'], ['1st reply'], ['2nd reply']]) | |
69 | ||
70 | ||
71 | class TestMakeChunk(unittest.TestCase): | |
72 | ||
73 | def testEmptyContent(self) -> None: | |
74 | with open('testdata/empty-content.html', 'rb') as f: | |
75 | t = Thread(spec_for_testing(f.read((9999)))) | |
76 | c = makeChunk(next(iter(t.chunkDOMs())), FakeImageStore()) | |
77 | self.assertEqual( | |
78 | c.icon, | |
79 | 'stored:https://d1anwqy6ci9o1i.cloudfront.net/' + | |
80 | 'users%2F366%2Ficons%2Fxqmypqvflgdy28aorw9ml_shock.png') | |
81 | assert c.character | |
82 | assert c.screen_name | |
83 | assert c.author | |
84 | self.assertEqual(list(c.character.stripped_strings), ['Keltham']) | |
85 | self.assertEqual( | |
86 | list(c.screen_name.stripped_strings), ['lawful chaotic']) | |
87 | self.assertEqual(list(c.author.stripped_strings), ['Iarwain']) | |
88 | self.assertEqual(str(c.content), | |
89 | '<div class="post-content"><p></p></div>') | |
90 | ||
91 | self.assertEqual( | |
92 | PandocTexifier("pandoc").texify(c.character), b'{Keltham}\n') | |
93 | ||
94 | def testMinimal(self) -> None: | |
95 | t = Thread(spec_for_testing(b''' | |
96 | <html><body> | |
97 | <div class="post-container post-post"> | |
98 | <div class="post-content">Just content</div> | |
99 | </div> | |
100 | </body></html>''')) | |
101 | c = makeChunk(next(iter(t.chunkDOMs())), FakeImageStore()) | |
102 | self.assertIsNone(c.icon) | |
103 | self.assertIsNone(c.character) | |
104 | self.assertIsNone(c.screen_name) | |
105 | self.assertIsNone(c.author) | |
106 | self.assertEqual(str(c.content), | |
107 | '<div class="post-content">Just content</div>') | |
108 | ||
109 | ||
110 | class TestThread(unittest.TestCase): | |
111 | ||
112 | def testTitle(self) -> None: | |
113 | t = Thread(spec_for_testing(b''' | |
114 | <html><body> | |
115 | <div class="content-header"> | |
116 | <span id="post-title"> | |
117 | <a href="/posts/1234">Teh Story!</a> | |
118 | </span> | |
119 | </div> | |
120 | <div class="post-container post-post">The "post"</div> | |
121 | </body></html>''')) | |
122 | self.assertEqual(t.title(), 'Teh Story!') | |
123 | ||
124 | def testNextThreadRelative(self) -> None: | |
125 | t = Thread(spec_for_testing(b''' | |
126 | <html><body> | |
127 | <div class="post-navheader"> | |
128 | <a class="view-button-link" href="/posts/4567"><div class="view-button">Next Post »</div> | |
129 | </a><a class="view-button-link" href="/posts/4321"><div class="view-button float-none">« Previous Post</div> | |
130 | </a> | |
131 | </div> | |
132 | <div class="post-container post-post">The "post"</div> | |
133 | </body></html>''')) | |
134 | self.assertEqual(t.next_thread(), 'https://fake/posts/4567') | |
135 | ||
136 | def testNextThreadAbsolute(self) -> None: | |
137 | t = Thread(spec_for_testing(b''' | |
138 | <html><body> | |
139 | <div class="post-navheader"> | |
140 | <a class="view-button-link" href="https://elsewhere/posts/4567"><div class="view-button">Next Post »</div> | |
141 | </a><a class="view-button-link" href="https://elsewhere/posts/4321"><div class="view-button float-none">« Previous Post</div> | |
142 | </a> | |
143 | </div> | |
144 | <div class="post-container post-post">The "post"</div> | |
145 | </body></html>''')) | |
146 | self.assertEqual(t.next_thread(), 'https://elsewhere/posts/4567') | |
147 | ||
148 | ||
149 | class TestEmit(unittest.TestCase): | |
150 | ||
151 | def testEmit(self) -> None: | |
152 | buf = BytesIO() | |
153 | Thread(spec_for_testing(b''' | |
154 | <html><body> | |
155 | <div class="post-container post-post"> | |
156 | <div class="post-content">A</div> | |
157 | </div> | |
158 | <div class="flat-post-replies"> | |
159 | <div class="post-container post-reply"> | |
160 | <div class="post-content">B</div> | |
161 | </div> | |
162 | </div> | |
163 | </body></html>''', buf)).emit() | |
164 | self.assertEqual(buf.getvalue(), rb'''\glowhead{}{}{}{}A | |
165 | \glowhead{}{}{}{}B | |
166 | ''') | |
167 | ||
168 | def testEmitTwoThreads(self) -> None: | |
169 | buf = BytesIO() | |
170 | spec = dataclasses.replace(spec_for_testing(b'', buf), fetcher=FakeFetcher({ | |
171 | 'https://fake/test': b'''<html><body> | |
172 | <div class="post-navheader"> | |
173 | <a class="view-button-link" href="/page2"><div class="view-button">Next Post »</div></a> | |
174 | </div></body></html>''', | |
175 | 'https://fake/test?view=flat': b'''<html><body> | |
176 | <div class="post-container post-post"><div class="post-content">A</div></div> | |
177 | <div class="flat-post-replies"> | |
178 | <div class="post-container post-reply"><div class="post-content">B</div></div> | |
179 | </div> | |
180 | </body></html>''', | |
181 | 'https://fake/page2': b'''<html><body></body></html>''', | |
182 | 'https://fake/page2?view=flat': b'''<html><body> | |
183 | <div class="post-container post-post"><div class="post-content">C</div></div> | |
184 | <div class="flat-post-replies"> | |
185 | <div class="post-container post-reply"><div class="post-content">D</div></div> | |
186 | <div class="post-container post-reply"><div class="post-content">E</div></div> | |
187 | </div> | |
188 | </body></html>''', | |
189 | })) | |
190 | Thread(spec).emit() | |
191 | self.assertEqual(buf.getvalue(), rb'''\glowhead{}{}{}{}A | |
192 | \glowhead{}{}{}{}B | |
193 | \glowhead{}{}{}{}C | |
194 | \glowhead{}{}{}{}D | |
195 | \glowhead{}{}{}{}E | |
196 | ''') | |
197 | ||
198 | ||
199 | if __name__ == '__main__': | |
200 | unittest.main() |