Merge branch 'development'
[django-tables2.git] / tests / core.py
1 """Test the core table functionality."""
2 import copy
3 from attest import Tests, Assert
4 from django.http import Http404
5 from django.core.paginator import Paginator
6 import django_tables2 as tables
7 from django_tables2 import utils
8
9
10 core = Tests()
11
12
13 class UnsortedTable(tables.Table):
14     i = tables.Column()
15     alpha = tables.Column()
16     beta = tables.Column()
17
18
19 class SortedTable(UnsortedTable):
20     class Meta:
21         order_by = 'alpha'
22
23
24 MEMORY_DATA = [
25     {'i': 2, 'alpha': 'b', 'beta': 'b'},
26     {'i': 1, 'alpha': 'a', 'beta': 'c'},
27     {'i': 3, 'alpha': 'c', 'beta': 'a'},
28 ]
29
30
31 @core.test
32 def declarations():
33     """Test defining tables by declaration."""
34     class GeoAreaTable(tables.Table):
35         name = tables.Column()
36         population = tables.Column()
37
38     assert len(GeoAreaTable.base_columns) == 2
39     assert 'name' in GeoAreaTable.base_columns
40     assert not hasattr(GeoAreaTable, 'name')
41
42     class CountryTable(GeoAreaTable):
43         capital = tables.Column()
44
45     assert len(CountryTable.base_columns) == 3
46     assert 'capital' in CountryTable.base_columns
47
48     # multiple inheritance
49     class AddedMixin(tables.Table):
50         added = tables.Column()
51
52     class CityTable(GeoAreaTable, AddedMixin):
53         mayor = tables.Column()
54
55     assert len(CityTable.base_columns) == 4
56     assert 'added' in CityTable.base_columns
57
58
59 @core.test
60 def attrs():
61     class TestTable(tables.Table):
62         class Meta:
63             attrs = {}
64     Assert({}) == TestTable([]).attrs
65
66     class TestTable2(tables.Table):
67         class Meta:
68             attrs = {"a": "b"}
69     Assert({"a": "b"}) == TestTable2([]).attrs
70
71     class TestTable3(tables.Table):
72         pass
73     Assert({}) == TestTable3([]).attrs
74     Assert({"a": "b"}) == TestTable3([], attrs={"a": "b"}).attrs
75
76     class TestTable4(tables.Table):
77         class Meta:
78             attrs = {"a": "b"}
79     Assert({"c": "d"}) == TestTable4([], attrs={"c": "d"}).attrs
80
81
82 @core.test
83 def datasource_untouched():
84     """Ensure that data that is provided to the table (the datasource) is not
85     modified by table operations.
86     """
87     original_data = copy.deepcopy(MEMORY_DATA)
88
89     table = UnsortedTable(MEMORY_DATA)
90     table.order_by = 'i'
91     list(table.rows)
92     assert MEMORY_DATA == Assert(original_data)
93
94     table = UnsortedTable(MEMORY_DATA)
95     table.order_by = 'beta'
96     list(table.rows)
97     assert MEMORY_DATA == Assert(original_data)
98
99
100 @core.test
101 def sorting():
102     # fallback to Table.Meta
103     Assert(('alpha', )) == SortedTable([], order_by=None).order_by == SortedTable([]).order_by
104
105     # values of order_by are wrapped in tuples before being returned
106     Assert(SortedTable([], order_by='alpha').order_by)   == ('alpha', )
107     Assert(SortedTable([], order_by=('beta',)).order_by) == ('beta', )
108
109     # "no sorting"
110     table = SortedTable([])
111     table.order_by = []
112     Assert(()) == table.order_by == SortedTable([], order_by=[]).order_by
113
114     table = SortedTable([])
115     table.order_by = ()
116     Assert(()) == table.order_by == SortedTable([], order_by=()).order_by
117
118     table = SortedTable([])
119     table.order_by = ''
120     Assert(()) == table.order_by == SortedTable([], order_by='').order_by
121
122     # apply a sorting
123     table = UnsortedTable([])
124     table.order_by = 'alpha'
125     Assert(('alpha', )) == UnsortedTable([], order_by='alpha').order_by == table.order_by
126
127     table = SortedTable([])
128     table.order_by = 'alpha'
129     Assert(('alpha', )) == SortedTable([], order_by='alpha').order_by  == table.order_by
130
131     # let's check the data
132     table = SortedTable(MEMORY_DATA, order_by='beta')
133     Assert(3) == table.rows[0]['i']
134
135     # allow fallback to Table.Meta.order_by
136     table = SortedTable(MEMORY_DATA)
137     Assert(1) == table.rows[0]['i']
138
139     # column's can't be sorted if they're not allowed to be
140     class TestTable(tables.Table):
141         a = tables.Column(sortable=False)
142         b = tables.Column()
143
144     table = TestTable([], order_by='a')
145     Assert(table.order_by) == ()
146
147     table = TestTable([], order_by='b')
148     Assert(table.order_by) == ('b', )
149
150     # sorting disabled by default
151     class TestTable(tables.Table):
152         a = tables.Column(sortable=True)
153         b = tables.Column()
154
155         class Meta:
156             sortable = False
157
158     table = TestTable([], order_by='a')
159     Assert(table.order_by) == ('a', )
160
161     table = TestTable([], order_by='b')
162     Assert(table.order_by) == ()
163
164     table = TestTable([], sortable=True, order_by='b')
165     Assert(table.order_by) == ('b', )
166
167
168 @core.test
169 def column_count():
170     class SimpleTable(tables.Table):
171         visible = tables.Column(visible=True)
172         hidden = tables.Column(visible=False)
173
174     # The columns container supports the len() builtin
175     assert len(SimpleTable([]).columns) == 1
176
177
178 @core.test
179 def column_accessor():
180     class SimpleTable(UnsortedTable):
181         col1 = tables.Column(accessor='alpha.upper.isupper')
182         col2 = tables.Column(accessor='alpha.upper')
183     table = SimpleTable(MEMORY_DATA)
184     row = table.rows[0]
185     Assert(row['col1']) is True
186     Assert(row['col2']) == 'B'
187
188
189 @core.test
190 def exclude_columns():
191     """
192     Defining ``Table.Meta.exclude`` or providing an ``exclude`` argument when
193     instantiating a table should have the same effect -- exclude those columns
194     from the table. It should have the same effect as not defining the
195     columns originally.
196     """
197     # Table(..., exclude=...)
198     table = UnsortedTable([], exclude=("i"))
199     Assert([c.name for c in table.columns]) == ["alpha", "beta"]
200
201     # Table.Meta: exclude=...
202     class PartialTable(UnsortedTable):
203         class Meta:
204             exclude = ("alpha", )
205     table = PartialTable([])
206     Assert([c.name for c in table.columns]) == ["i", "beta"]
207
208     # Inheritence -- exclude in parent, add in child
209     class AddonTable(PartialTable):
210         added = tables.Column()
211     table = AddonTable([])
212     Assert([c.name for c in table.columns]) == ["i", "beta", "added"]
213
214     # Inheritence -- exclude in child
215     class ExcludeTable(UnsortedTable):
216         added = tables.Column()
217         class Meta:
218             exclude = ("alpha", )
219     table = ExcludeTable([])
220     Assert([c.name for c in table.columns]) == ["i", "beta", "added"]
221
222
223 @core.test
224 def pagination():
225     class BookTable(tables.Table):
226         name = tables.Column()
227
228     # create some sample data
229     data = []
230     for i in range(100):
231         data.append({"name": "Book No. %d" % i})
232     books = BookTable(data)
233
234     # external paginator
235     paginator = Paginator(books.rows, 10)
236     assert paginator.num_pages == 10
237     page = paginator.page(1)
238     assert page.has_previous() is False
239     assert page.has_next() is True
240
241     # integrated paginator
242     books.paginate(page=1)
243     Assert(hasattr(books, "page")) is True
244
245     books.paginate(page=1, per_page=10)
246     Assert(len(list(books.page.object_list))) == 10
247
248     # new attributes
249     Assert(books.paginator.num_pages) == 10
250     Assert(books.page.has_previous()) is False
251     Assert(books.page.has_next()) is True
252
253     # exceptions are converted into 404s
254     with Assert.raises(Http404) as error:
255         books.paginate(Paginator, page=9999, per_page=10)
256         books.paginate(Paginator, page='abc', per_page=10)
257
258
259 @core.test
260 def empty_text():
261     class TestTable(tables.Table):
262         a = tables.Column()
263
264     table = TestTable([])
265     Assert(table.empty_text) is None
266
267     class TestTable(tables.Table):
268         a = tables.Column()
269
270         class Meta:
271             empty_text = 'nothing here'
272
273     table = TestTable([])
274     Assert(table.empty_text) == 'nothing here'
275
276     table = TestTable([], empty_text='still nothing')
277     Assert(table.empty_text) == 'still nothing'