]> git.scottworley.com Git - paperdoorknob/blame - glowfic_test.py
Handle Unicode characters ≈ and ◁
[paperdoorknob] / glowfic_test.py
CommitLineData
e6adf6ce
SW
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
6f430a74 7import dataclasses
d6e27f4b 8from io import BytesIO
19ed28f3 9from sys import stderr
e6adf6ce
SW
10import unittest
11
d6e27f4b
SW
12from typing import Optional
13
19ed28f3 14from fetch import FakeFetcher
aa060d9b 15from images import FakeImageStore
94027099 16from glowfic import makeChunk, Thread
19ed28f3 17from spec import Spec
62043b2b 18from texify import PandocTexifier
e6adf6ce
SW
19
20
d6e27f4b 21def spec_for_testing(html: bytes, outbuf: Optional[BytesIO] = None) -> Spec:
075f2f08
SW
22 return Spec('https://fake/test',
23 FakeFetcher({'https://fake/test': html,
24 'https://fake/test?view=flat': html}),
19ed28f3
SW
25 FakeImageStore(),
26 lambda x: x,
27 lambda x: None,
28 PandocTexifier('pandoc'),
29 lambda x: x,
30 20,
31 b'',
32 None,
d6e27f4b 33 stderr.buffer if outbuf is None else outbuf,
19ed28f3
SW
34 lambda x: None)
35
36
e6adf6ce
SW
37class TestSplit(unittest.TestCase):
38
39 def testSplit1(self) -> None:
19ed28f3 40 t = Thread(spec_for_testing(b'''
e6adf6ce
SW
41 <html><body><div class="post-container post-post">
42 The "post"
19ed28f3 43 </div></body></html>'''))
94027099 44 self.assertEqual([list(t.stripped_strings) for t in t.chunkDOMs()],
e6adf6ce
SW
45 [['The "post"']])
46
47 def testSplit2(self) -> None:
19ed28f3 48 t = Thread(spec_for_testing(b'''
e6adf6ce
SW
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>
19ed28f3 54 </body></html>'''))
94027099 55 self.assertEqual([list(t.stripped_strings) for t in t.chunkDOMs()],
e6adf6ce
SW
56 [['The "post"'], ['The "reply"']])
57
58 def testSplit3(self) -> None:
19ed28f3 59 t = Thread(spec_for_testing(b'''
e6adf6ce
SW
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>
19ed28f3 66 </body></html>'''))
94027099 67 self.assertEqual([list(t.stripped_strings) for t in t.chunkDOMs()],
e6adf6ce
SW
68 [['The "post"'], ['1st reply'], ['2nd reply']])
69
70
aa060d9b
SW
71class TestMakeChunk(unittest.TestCase):
72
73 def testEmptyContent(self) -> None:
74 with open('testdata/empty-content.html', 'rb') as f:
19ed28f3 75 t = Thread(spec_for_testing(f.read((9999))))
94027099 76 c = makeChunk(next(iter(t.chunkDOMs())), FakeImageStore())
aa060d9b
SW
77 self.assertEqual(
78 c.icon,
79 'stored:https://d1anwqy6ci9o1i.cloudfront.net/' +
80 'users%2F366%2Ficons%2Fxqmypqvflgdy28aorw9ml_shock.png')
37c47bc2
SW
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'])
aa060d9b
SW
88 self.assertEqual(str(c.content),
89 '<div class="post-content"><p></p></div>')
90
62043b2b
SW
91 self.assertEqual(
92 PandocTexifier("pandoc").texify(c.character), b'{Keltham}\n')
93
0668adb7
SW
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
aa060d9b 109
21e82200
SW
110class TestThread(unittest.TestCase):
111
112 def testTitle(self) -> None:
19ed28f3 113 t = Thread(spec_for_testing(b'''
21e82200
SW
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>
19ed28f3 121 </body></html>'''))
21e82200
SW
122 self.assertEqual(t.title(), 'Teh Story!')
123
fc2aaa75 124 def testNextThreadRelative(self) -> None:
53f396b4
SW
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>'''))
fc2aaa75
SW
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')
53f396b4 147
21e82200 148
d6e27f4b
SW
149class 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
6f430a74
SW
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
d6e27f4b 198
e6adf6ce
SW
199if __name__ == '__main__':
200 unittest.main()