a97c41711d0b506793d9acd7125d4f1207e11946
[wolnelektury.git] / apps / catalogue / tests / book_import.py
1 # -*- coding: utf-8 -*-
2 from __future__ import with_statement
3
4 from django.core.files.base import ContentFile, File
5 from catalogue.test_utils import *
6 from catalogue import models
7 from librarian import WLURI
8
9 from nose.tools import raises
10 import tempfile
11 from os import unlink, path, makedirs
12
13 class BookImportLogicTests(WLTestCase):
14
15     def setUp(self):
16         WLTestCase.setUp(self)
17         self.book_info = BookInfoStub(
18             url=WLURI.from_slug_and_lang(u"default-book", None),
19             about=u"http://wolnelektury.pl/example/URI/default_book",
20             title=u"Default Book",
21             author=PersonStub(("Jim",), "Lazy"),
22             kind="X-Kind",
23             genre="X-Genre",
24             epoch="X-Epoch",
25             language=u"pol",
26         )
27
28         self.expected_tags = [
29            ('author', 'jim-lazy'),
30            ('genre', 'x-genre'),
31            ('epoch', 'x-epoch'),
32            ('kind', 'x-kind'),
33         ]
34         self.expected_tags.sort()
35
36     def test_empty_book(self):
37         BOOK_TEXT = "<utwor />"
38         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
39
40         self.assertEqual(book.title, "Default Book")
41         self.assertEqual(book.slug, "default-book")
42         self.assert_(book.parent is None)
43         self.assertFalse(book.has_html_file())
44
45         # no fragments generated
46         self.assertEqual(book.fragments.count(), 0)
47
48         # TODO: this should be filled out probably...
49         self.assertEqual(book.wiki_link, '')
50         self.assertEqual(book.gazeta_link, '')
51         self.assertEqual(book.description, '')
52
53         tags = [ (tag.category, tag.slug) for tag in book.tags ]
54         tags.sort()
55
56         self.assertEqual(tags, self.expected_tags)
57
58     def test_not_quite_empty_book(self):
59         """ Not empty, but without any real text.
60
61         Should work like any other non-empty book.
62         """
63
64         BOOK_TEXT = """<utwor>
65         <liryka_l>
66             <nazwa_utworu>Nic</nazwa_utworu>
67         </liryka_l></utwor>
68         """
69
70         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
71         self.assertTrue(book.has_html_file())
72
73     def test_book_with_fragment(self):
74         BOOK_TEXT = """<utwor>
75         <opowiadanie>
76             <akap><begin id="m01" /><motyw id="m01">Love</motyw>Ala ma kota<end id="m01" /></akap>
77         </opowiadanie></utwor>
78         """
79
80         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
81         self.assertTrue(book.has_html_file())
82
83         self.assertEqual(book.fragments.count(), 1)
84         self.assertEqual(book.fragments.all()[0].text, u'<p class="paragraph">Ala ma kota</p>\n')
85
86         self.assert_(('theme', 'love') in [ (tag.category, tag.slug) for tag in book.fragments.all()[0].tags ])
87
88     def test_book_with_empty_theme(self):
89         """ empty themes should be ignored """
90
91         BOOK_TEXT = """<utwor>
92         <opowiadanie>
93             <akap><begin id="m01" /><motyw id="m01"> , Love , , </motyw>Ala ma kota<end id="m01" /></akap>
94         </opowiadanie></utwor>
95         """
96
97         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
98         self.assert_([('theme', 'love')],
99                          [ (tag.category, tag.slug) for tag in book.fragments.all()[0].tags.filter(category='theme') ])
100
101     def test_book_with_no_theme(self):
102         """ fragments with no themes shouldn't be created at all """
103
104         BOOK_TEXT = """<utwor>
105         <opowiadanie>
106             <akap><begin id="m01" /><motyw id="m01"></motyw>Ala ma kota<end id="m01" /></akap>
107         </opowiadanie></utwor>
108         """
109
110         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
111         self.assertEqual(book.fragments.count(), 0)
112         self.assertEqual(book.tags.filter(category='theme').count(), 0)
113
114     @raises(ValueError)
115     def test_book_with_invalid_slug(self):
116         """ Book with invalid characters in slug shouldn't be imported """
117         self.book_info.url = WLURI.from_slug_and_lang(u"default_book", None)
118         BOOK_TEXT = "<utwor />"
119         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
120
121     def test_book_replace_title(self):
122         BOOK_TEXT = """<utwor />"""
123         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
124         self.book_info.title = u"Extraordinary"
125         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info, overwrite=True)
126
127         tags = [ (tag.category, tag.slug) for tag in book.tags ]
128         tags.sort()
129
130         self.assertEqual(tags, self.expected_tags)
131
132     def test_book_replace_author(self):
133         BOOK_TEXT = """<utwor />"""
134         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
135         self.book_info.author = PersonStub(("Hans", "Christian"), "Andersen")
136         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info, overwrite=True)
137
138         tags = [ (tag.category, tag.slug) for tag in book.tags ]
139         tags.sort()
140
141         self.expected_tags.remove(('author', 'jim-lazy'))
142         self.expected_tags.append(('author', 'hans-christian-andersen'))
143         self.expected_tags.sort()
144
145         self.assertEqual(tags, self.expected_tags)
146
147         # the old tag shouldn't disappear
148         models.Tag.objects.get(slug="jim-lazy", category="author")
149
150     def test_book_remove_fragment(self):
151         BOOK_TEXT = """<utwor>
152         <opowiadanie>
153             <akap>
154                 <begin id="m01" /><motyw id="m01">Love</motyw>Ala ma kota<end id="m01" />
155                 <begin id="m02" /><motyw id="m02">Hatred</motyw>To kot Ali<end id="m02" />
156             </akap>
157         </opowiadanie></utwor>
158         """
159         BOOK_TEXT_AFTER = """<utwor>
160         <opowiadanie>
161             <akap>
162                 <begin id="m01" /><motyw id="m01">Love</motyw>Ala ma kota<end id="m01" />
163                 To kot Ali
164             </akap>
165         </opowiadanie></utwor>
166         """
167
168         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
169         self.assertEqual(book.fragments.count(), 2)
170         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT_AFTER), self.book_info, overwrite=True)
171         self.assertEqual(book.fragments.count(), 1)
172
173     def test_multiple_tags(self):
174         BOOK_TEXT = """<utwor />"""
175         self.book_info.authors = self.book_info.author, PersonStub(("Joe",), "Dilligent"),
176         self.book_info.kinds = self.book_info.kind, 'Y-Kind',
177         self.book_info.genres = self.book_info.genre, 'Y-Genre',
178         self.book_info.epochs = self.book_info.epoch, 'Y-Epoch',
179
180         self.expected_tags.extend([
181            ('author', 'joe-dilligent'),
182            ('genre', 'y-genre'),
183            ('epoch', 'y-epoch'),
184            ('kind', 'y-kind'),
185         ])
186         self.expected_tags.sort()
187
188         book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
189         tags = [ (tag.category, tag.slug) for tag in book.tags ]
190         tags.sort()
191
192         self.assertEqual(tags, self.expected_tags)
193
194
195 class ChildImportTests(WLTestCase):
196
197     def setUp(self):
198         WLTestCase.setUp(self)
199         self.child_info = BookInfoStub(
200             genre='X-Genre',
201             epoch='X-Epoch',
202             kind='X-Kind',
203             author=PersonStub(("Joe",), "Doe"),
204             **info_args("Child")
205         )
206
207         self.parent_info = BookInfoStub(
208             genre='X-Genre',
209             epoch='X-Epoch',
210             kind='X-Kind',
211             author=PersonStub(("Jim",), "Lazy"),
212             parts=[self.child_info.url],
213             **info_args("Parent")
214         )
215
216     def test_child(self):
217         TEXT = """<utwor />"""
218         child = models.Book.from_text_and_meta(ContentFile(TEXT), self.child_info)
219         parent = models.Book.from_text_and_meta(ContentFile(TEXT), self.parent_info)
220         author = parent.tags.get(category='author')
221         books = self.client.get(author.get_absolute_url()).context['object_list']
222         self.assertEqual(len(books), 1,
223                         "Only parent book should be visible on author's page")
224
225     def test_child_replace(self):
226         PARENT_TEXT = """<utwor />"""
227         CHILD_TEXT = """<utwor>
228         <opowiadanie>
229             <akap><begin id="m01" /><motyw id="m01">Pies</motyw>Ala ma kota<end id="m01" /></akap>
230         </opowiadanie></utwor>
231         """
232         child = models.Book.from_text_and_meta(ContentFile(CHILD_TEXT), self.child_info)
233         parent = models.Book.from_text_and_meta(ContentFile(PARENT_TEXT), self.parent_info)
234         CHILD_TEXT = """<utwor>
235         <opowiadanie>
236             <akap><begin id="m01" /><motyw id="m01">Kot</motyw>Ala ma kota<end id="m01" /></akap>
237         </opowiadanie></utwor>
238         """
239         child = models.Book.from_text_and_meta(ContentFile(CHILD_TEXT), self.child_info, overwrite=True)
240
241         themes = self.client.get(parent.get_absolute_url()).context['book_themes']
242
243         self.assertEqual(['Kot'], [tag.name for tag in themes],
244                         'wrong related theme list')
245
246
247 class MultilingualBookImportTest(WLTestCase):
248     def setUp(self):
249         WLTestCase.setUp(self)
250         self.pol_info = BookInfoStub(
251             genre='X-Genre',
252             epoch='X-Epoch',
253             kind='X-Kind',
254             author=PersonStub(("Joe",), "Doe"),
255             **info_args("A book")
256         )
257
258         self.eng_info = BookInfoStub(
259             genre='X-Genre',
260             epoch='X-Epoch',
261             kind='X-Kind',
262             author=PersonStub(("Joe",), "Doe"),
263             **info_args("A book", "eng")
264         )
265
266     def test_multilingual_import(self):
267         BOOK_TEXT = """<utwor><opowiadanie><akap>A</akap></opowiadanie></utwor>"""
268
269         book1 = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.pol_info)
270         book2 = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.eng_info)
271
272         self.assertEqual(
273                 set([b.language for b in models.Book.objects.all()]),
274                 set(['pol', 'eng']),
275                 'Books imported in wrong languages.'
276             )
277
278
279 class BookImportGenerateTest(WLTestCase):
280     def setUp(self):
281         WLTestCase.setUp(self)
282         input = path.join(path.dirname(__file__), 'files/fraszka-do-anusie.xml')
283         self.book = models.Book.from_xml_file(input)
284
285     def test_gen_pdf(self):
286         self.book.build_pdf()
287         self.assertTrue(path.exists(self.book.pdf_file.path))
288
289     def test_gen_pdf_parent(self):
290         """This book contains a child."""
291         input = path.join(path.dirname(__file__), "files/fraszki.xml")
292         parent = models.Book.from_xml_file(input)
293         parent.build_pdf()
294         self.assertTrue(path.exists(parent.pdf_file.path))
295
296     def test_custom_pdf(self):
297         out = models.get_dynamic_path(None, 'test-custom', ext='pdf')
298         absoulute_path = path.join(settings.MEDIA_ROOT, out)
299         
300         if not path.exists(path.dirname(absoulute_path)):
301             makedirs(path.dirname(absoulute_path))
302
303         self.book.build_pdf(customizations=['nofootnotes', '13pt', 'a4paper'], file_name=out)
304         self.assertTrue(path.exists(absoulute_path))