def test_get_page_empty_object_list_and_allow_empty_first_page_false(self): """ Paginator.get_page() raises EmptyPage if allow_empty_first_page=False and object_list is empty. """ paginator = Paginator([], 2, allow_empty_first_page=False) with self.assertRaises(EmptyPage): paginator.get_page(1)
def test_get_page_empty_object_list(self): """Paginator.get_page() with an empty object_list.""" paginator = Paginator([], 2) # An empty page returns the last page. self.assertEqual(paginator.get_page(1).number, 1) self.assertEqual(paginator.get_page(2).number, 1) # Non-integer page returns the first page. self.assertEqual(paginator.get_page(None).number, 1)
def test_get_page(self): """ Paginator.get_page() returns a valid page even with invalid page arguments. """ paginator = Paginator([1, 2, 3], 2) page = paginator.get_page(1) self.assertEqual(page.number, 1) self.assertEqual(page.object_list, [1, 2]) # An empty page returns the last page. self.assertEqual(paginator.get_page(3).number, 2) # Non-integer page returns the first page. self.assertEqual(paginator.get_page(None).number, 1)
def test_invalid_page_number(self): """ Invalid page numbers result in the correct exception being raised. """ paginator = Paginator([1, 2, 3], 2) with self.assertRaises(InvalidPage): paginator.page(3) with self.assertRaises(PageNotAnInteger): paginator.validate_number(None) with self.assertRaises(PageNotAnInteger): paginator.validate_number('x') with self.assertRaises(PageNotAnInteger): paginator.validate_number(1.2)
def test_last_page(self): paginator = Paginator(Article.objects.order_by('id'), 5) p = paginator.page(2) self.assertEqual("<Page 2 of 2>", str(p)) self.assertQuerysetEqual(p.object_list, [ "<Article: Article 6>", "<Article: Article 7>", "<Article: Article 8>", "<Article: Article 9>" ]) self.assertFalse(p.has_next()) self.assertTrue(p.has_previous()) self.assertTrue(p.has_other_pages()) with self.assertRaises(InvalidPage): p.next_page_number() self.assertEqual(1, p.previous_page_number()) self.assertEqual(6, p.start_index()) self.assertEqual(9, p.end_index())
def test_count_does_not_silence_type_error(self): class TypeErrorContainer: def count(self): raise TypeError('abc') with self.assertRaisesMessage(TypeError, 'abc'): Paginator(TypeErrorContainer(), 10).count()
def test_count_does_not_silence_attribute_error(self): class AttributeErrorContainer: def count(self): raise AttributeError('abc') with self.assertRaisesMessage(AttributeError, 'abc'): Paginator(AttributeErrorContainer(), 10).count()
def test_paginating_unordered_queryset_raises_warning(self): msg = ("Pagination may yield inconsistent results with an unordered " "object_list: <class 'pagination.models.Article'> QuerySet.") with self.assertWarnsMessage(UnorderedObjectListWarning, msg) as cm: Paginator(Article.objects.all(), 5) # The warning points at the Paginator caller (i.e. the stacklevel # is appropriate). self.assertEqual(cm.filename, __file__)
def test_page_sequence(self): """ A paginator page acts like a standard sequence. """ eleven = 'abcdefghijk' page2 = Paginator(eleven, per_page=5, orphans=1).page(2) self.assertEqual(len(page2), 6) self.assertIn('k', page2) self.assertNotIn('a', page2) self.assertEqual(''.join(page2), 'fghijk') self.assertEqual(''.join(reversed(page2)), 'kjihgf')
def test_paginate_misc_classes(self): class CountContainer: def count(self): return 42 # Paginator can be passed other objects with a count() method. paginator = Paginator(CountContainer(), 10) self.assertEqual(42, paginator.count) self.assertEqual(5, paginator.num_pages) self.assertEqual([1, 2, 3, 4, 5], list(paginator.page_range)) # Paginator can be passed other objects that implement __len__. class LenContainer: def __len__(self): return 42 paginator = Paginator(LenContainer(), 10) self.assertEqual(42, paginator.count) self.assertEqual(5, paginator.num_pages) self.assertEqual([1, 2, 3, 4, 5], list(paginator.page_range))
def check_indexes(self, params, page_num, indexes): """ Helper method that instantiates a Paginator object from the passed params and then checks that the start and end indexes of the passed page_num match those given as a 2-tuple in indexes. """ paginator = Paginator(*params) if page_num == 'first': page_num = 1 elif page_num == 'last': page_num = paginator.num_pages page = paginator.page(page_num) start, end = indexes msg = ( "For %s of page %s, expected %s but got %s. Paginator parameters were: %s" ) self.assertEqual( start, page.start_index(), msg % ('start index', page_num, start, page.start_index(), params)) self.assertEqual( end, page.end_index(), msg % ('end index', page_num, end, page.end_index(), params))
def test_paginating_unordered_object_list_raises_warning(self): """ Unordered object list warning with an object that has an ordered attribute but not a model attribute. """ class ObjectList: ordered = False object_list = ObjectList() msg = ("Pagination may yield inconsistent results with an unordered " "object_list: {!r}.".format(object_list)) with self.assertWarnsMessage(UnorderedObjectListWarning, msg): Paginator(object_list, 5)
def check_paginator(self, params, output): """ Helper method that instantiates a Paginator object from the passed params and then checks that its attributes match the passed output. """ count, num_pages, page_range = output paginator = Paginator(*params) self.check_attribute('count', paginator, count, params) self.check_attribute('num_pages', paginator, num_pages, params) self.check_attribute('page_range', paginator, page_range, params, coerce=list)
def test_page_getitem(self): """ Tests proper behavior of a paginator page __getitem__ (queryset evaluation, slicing, exception raised). """ paginator = Paginator(Article.objects.order_by('id'), 5) p = paginator.page(1) # Make sure object_list queryset is not evaluated by an invalid __getitem__ call. # (this happens from the template engine when using eg: {% page_obj.has_previous %}) self.assertIsNone(p.object_list._result_cache) with self.assertRaises(TypeError): p['has_previous'] self.assertIsNone(p.object_list._result_cache) self.assertNotIsInstance(p.object_list, list) # Make sure slicing the Page object with numbers and slice objects work. self.assertEqual(p[0], Article.objects.get(headline='Article 1')) self.assertQuerysetEqual(p[slice(2)], [ "<Article: Article 1>", "<Article: Article 2>", ]) # After __getitem__ is called, object_list is a list self.assertIsInstance(p.object_list, list)
def test_page_range_iterator(self): """ Paginator.page_range should be an iterator. """ self.assertIsInstance( Paginator([1, 2, 3], 2).page_range, type(range(0)))
def test_paginating_empty_queryset_does_not_warn(self): with warnings.catch_warnings(record=True) as recorded: Paginator(Article.objects.none(), 5) self.assertEqual(len(recorded), 0)
def test_no_content_allow_empty_first_page(self): # With no content and allow_empty_first_page=True, 1 is a valid page number paginator = Paginator([], 2) self.assertEqual(paginator.validate_number(1), 1)
def test_float_integer_page(self): paginator = Paginator([1, 2, 3], 2) self.assertEqual(paginator.validate_number(1.0), 1)