]> git.scottworley.com Git - paperdoorknob/blob - glowfic_test.py
Handle Unicode characters ≈ and ◁
[paperdoorknob] / glowfic_test.py
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 &raquo;</div>
129 </a><a class="view-button-link" href="/posts/4321"><div class="view-button float-none">&laquo; 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 &raquo;</div>
141 </a><a class="view-button-link" href="https://elsewhere/posts/4321"><div class="view-button float-none">&laquo; 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 &raquo;</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()