1 # This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
4 from unittest import skip
6 from django.core.files.base import ContentFile
7 from django.test import Client
8 from catalogue import models
9 from catalogue.test_utils import *
12 class BooksByTagTests(WLTestCase):
13 """ tests the /katalog/category/tag page for found books """
16 WLTestCase.setUp(self)
17 author = PersonStub(("Common",), "Man")
20 self.gchild_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Kind', author=author,
21 **info_args("GChild"))
23 self.child_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Other Kind', author=author,
24 parts=[self.gchild_info.url],
27 self.parent_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Kind', author=author,
28 parts=[self.child_info.url],
29 **info_args("Parent"))
31 self.book_file = ContentFile(b'<utwor />')
33 def test_nonexistent_tag(self):
34 """ Looking for a non-existent tag should yield 404 """
35 self.assertEqual(404, self.client.get('/katalog/autor/czeslaw-milosz/').status_code)
37 def test_book_tag(self):
38 """ Looking for a book tag isn't permitted """
39 models.Book.from_text_and_meta(self.book_file, self.gchild_info)
40 self.assertEqual(404, self.client.get('/katalog/gchild/').status_code)
42 def test_tag_empty(self):
43 """ Tag with no books should return no books """
44 models.Book.from_text_and_meta(self.book_file, self.gchild_info)
45 models.Tag.objects.create(name='Empty tag', slug='empty', category='author')
47 context = self.client.get('/katalog/autor/empty/').context
48 self.assertEqual(0, len(context['object_list']))
50 def test_tag_eliminate(self):
51 """ Filtering by tag should only yield top-level qualifying books. """
52 for info in self.gchild_info, self.child_info, self.parent_info:
53 models.Book.from_text_and_meta(self.book_file, info)
56 context = self.client.get('/katalog/gatunek/genre/').context
57 self.assertEqual([book.title for book in context['object_list']],
60 # parent and gchild qualify, child doesn't
61 context = self.client.get('/katalog/rodzaj/kind/').context
62 self.assertEqual([book.title for book in context['object_list']],
65 # Filtering by child's tag should yield the child
66 context = self.client.get('/katalog/rodzaj/other-kind/').context
67 self.assertEqual([book.title for book in context['object_list']],
71 class TagRelatedTagsTests(WLTestCase):
72 """ tests the /katalog/category/tag/ page for related tags """
75 WLTestCase.setUp(self)
76 self.client = Client()
77 author = PersonStub(("Common",), "Man")
79 gchild_info = BookInfoStub(author=author, genre="GchildGenre", epoch='Epoch', kind="Kind",
80 **info_args("GChild"))
81 child1_info = BookInfoStub(author=author, genre="ChildGenre", epoch='Epoch', kind="ChildKind",
82 parts=[gchild_info.url],
83 **info_args("Child1"))
84 child2_info = BookInfoStub(author=author, genre="ChildGenre", epoch='Epoch', kind="ChildKind",
85 **info_args("Child2"))
86 parent_info = BookInfoStub(author=author, genre="Genre", epoch='Epoch', kind="Kind",
87 parts=[child1_info.url, child2_info.url],
88 **info_args("Parent"))
90 for info in gchild_info, child1_info, child2_info, parent_info:
91 book_text = """<utwor><opowiadanie><akap>
93 <motyw id="m01">Theme, %sTheme</motyw>
96 </akap></opowiadanie></utwor>
98 book = models.Book.from_text_and_meta(
99 ContentFile(book_text.encode('utf-8')),
104 tag_empty = models.Tag(name='Empty tag', slug='empty', category='author')
107 def test_empty(self):
108 """ empty tag should have no related tags """
110 suggested = self.client.get('/katalog/autor/empty/').context['suggested_tags']
111 self.assertEqual(suggested, [], 'tags related to empty tag')
113 def test_has_related(self):
114 """ related own and descendants' tags should be generated """
118 for t in self.client.get('/katalog/rodzaj/kind/').context['suggested_tags']
120 self.assertTrue(('Common Man', 'author') in suggested,
121 'missing `author` related tag')
122 self.assertTrue(('Epoch', 'epoch') in suggested,
123 'missing `epoch` related tag')
124 # TODO: this should probably be changed now.
125 self.assertFalse(any(x for x in suggested if x[1] == "kind"),
126 "There should be no child-only related `kind` tags")
127 self.assertTrue(("Genre", 'genre') in suggested,
128 'missing `genre` related tag')
129 # TODO: this should probably be changed now.
130 self.assertFalse(("ChildGenre", 'genre') in suggested,
131 "There should be no child-only related `genre` tags")
132 self.assertTrue(("GchildGenre", "genre") in suggested,
133 "missing grandchild's related tag")
134 self.assertTrue(('Theme', 'theme') in suggested,
135 "missing related theme")
136 self.assertTrue(('Child1Theme', 'theme') in suggested,
137 "missing child's related theme")
138 self.assertTrue(('GChildTheme', 'theme') in suggested,
139 "missing grandchild's related theme")
141 def test_related_differ(self):
142 """ related tags shouldn't include filtering tags """
144 response = self.client.get('/katalog/rodzaj/kind/')
145 suggested = response.context['suggested_tags']
146 self.assertFalse(any(x for x in suggested if x.category == 'kind'),
147 'filtering tag wrongly included in related')
150 for t in self.client.get(
151 '/katalog/motyw/theme/').context['suggested_tags']
153 self.assertFalse(('Theme', 'theme') in suggested,
154 'filtering theme wrongly included in related')
156 def test_parent_tag_once(self):
157 """ if parent and descendants have a common tag, count it only once """
159 suggested = self.client.get('/katalog/rodzaj/kind/').context['suggested_tags']
160 self.assertEqual([(tag.name, tag.count) for tag in suggested if tag.category == 'epoch'],
162 'wrong related tag epoch tag on tag page')
164 def test_siblings_tags_count(self):
165 """ if children have tags and parent hasn't, count the children """
167 suggested = self.client.get('/katalog/epoka/epoch/').context['suggested_tags']
168 kinds = [(tag.name, tag.count) for tag in suggested if tag.category == 'kind']
170 ('ChildKind', 2) in kinds,
171 'wrong related kind tags on tag page'
174 # all occurencies of theme should be counted
175 themes = [(tag.name, tag.count) for tag in suggested if tag.category == 'theme']
177 ('Theme', 4) in themes,
178 'wrong related theme count'
181 def test_query_child_tag(self):
183 If child and parent have a common tag, but parent isn't included
184 in the result, child should still count.
186 suggested = self.client.get('/katalog/gatunek/childgenre/').context['suggested_tags']
187 epochs = [(tag.name, tag.count) for tag in suggested if tag.category == 'epoch']
189 ('Epoch', 2) in epochs,
190 'wrong related kind tags on tag page'
194 class CleanTagRelationTests(WLTestCase):
195 """ tests for tag relations cleaning after deleting things """
198 WLTestCase.setUp(self)
199 author = PersonStub(("Common",), "Man")
201 book_info = BookInfoStub(author=author, genre="G", epoch='E', kind="K", **info_args("Book"))
202 book_text = """<utwor><opowiadanie><akap>
203 <begin id="m01" /><motyw id="m01">Theme</motyw>Ala ma kota
205 </akap></opowiadanie></utwor>
207 self.book = models.Book.from_text_and_meta(
208 ContentFile(book_text.encode('utf-8')),
211 @skip('Not implemented and not priority')
212 def test_delete_objects(self):
213 """ there should be no related tags left after deleting some objects """
215 models.Book.objects.all().delete()
216 suggested = self.client.get('/katalog/rodzaj/k/').context['suggested_tags']
217 self.assertEqual(suggested, [])
218 self.assertEqual(models.Fragment.objects.all().count(), 0,
219 "orphaned fragments left")
220 self.assertEqual(models.Tag.intermediary_table_model.objects.all().count(), 0,
221 "orphaned TagRelation objects left")
223 def test_deleted_tag(self):
224 """ there should be no tag relations left after deleting tags """
226 models.Tag.objects.all().delete()
227 self.assertEqual(len(self.book.related_themes()), 0)
228 self.assertEqual(models.Tag.intermediary_table_model.objects.all().count(), 0,
229 "orphaned TagRelation objects left")
232 class TestIdenticalTag(WLTestCase):
235 WLTestCase.setUp(self)
236 author = PersonStub((), "Tag")
238 self.book_info = BookInfoStub(author=author, genre="tag", epoch='tag', kind="tag", **info_args("tag"))
239 self.book_text = """<utwor>
242 <begin id="m01" /><motyw id="m01">tag</motyw>Ala ma kota<end id="m01" />
248 def test_book_tags(self):
249 """ there should be all related tags in relevant categories """
250 book = models.Book.from_text_and_meta(
251 ContentFile(self.book_text.encode('utf-8')),
254 related_themes = book.related_themes()
255 for category in 'author', 'kind', 'genre', 'epoch':
256 self.assertTrue('tag' in book.tags.filter(category=category).values_list('slug', flat=True),
257 'missing related tag for %s' % category)
258 self.assertTrue('tag' in [tag.slug for tag in related_themes])
260 def test_qualified_url(self):
261 models.Book.from_text_and_meta(
262 ContentFile(self.book_text.encode('utf-8')),
264 categories = {'author': 'autor', 'theme': 'motyw', 'epoch': 'epoka', 'kind': 'rodzaj', 'genre': 'gatunek'}
265 for cat, localcat in categories.items():
266 if cat == 'theme': continue
267 context = self.client.get('/katalog/%s/tag/' % localcat).context
268 self.assertEqual(1, len(context['object_list']))
269 self.assertNotEqual([], context['suggested_tags'])
270 self.assertFalse(any(t for t in context['suggested_tags'] if t.category == cat))
273 class BookTagsTests(WLTestCase):
274 """ tests the /katalog/lektura/book/ page for related tags """
277 WLTestCase.setUp(self)
278 author1 = PersonStub(("Common",), "Man")
279 author2 = PersonStub(("Jim",), "Lazy")
281 child_info = BookInfoStub(authors=(author1, author2), genre="ChildGenre", epoch='Epoch', kind="ChildKind",
282 **info_args("Child"))
283 parent_info = BookInfoStub(author=author1, genre="Genre", epoch='Epoch', kind="Kind",
284 parts=[child_info.url],
285 **info_args("Parent"))
287 for info in child_info, parent_info:
288 book_text = """<utwor><opowiadanie><akap>
290 <motyw id="m01">Theme, %sTheme</motyw>
293 </akap></opowiadanie></utwor>
295 models.Book.from_text_and_meta(
296 ContentFile(book_text.encode('utf-8')),
299 def test_book_tags(self):
300 """ book should have own tags and whole tree's themes """
302 book = models.Book.objects.get(slug='parent')
303 related_themes = book.related_themes()
305 self.assertEqual([t.slug for t in book.authors()],
307 self.assertEqual([t.slug for t in book.tags.filter(category='kind')],
309 self.assertEqual([(tag.name, tag.count) for tag in related_themes],
310 [('Theme', 2), ('ChildTheme', 1), ('ParentTheme', 1)])