1#!/usr/bin/env python 2#coding:utf-8 3# Purpose: test table 4# Created: 20.01.2011 5# Copyright (C) 2011, Manfred Moitzi 6# License: MIT license 7from __future__ import unicode_literals, print_function, division 8__author__ = "mozman <mozman@gmx.at>" 9 10# Standard Library 11try: 12 import unittest2 as unittest 13except ImportError: 14 import unittest 15 16from itertools import chain 17 18# trusted or separately tested modules 19from ezodf.xmlns import CN, etree, wrap 20from ezodf.compatibility import is_string 21 22# objects to test 23from ezodf.cells import Cell 24from ezodf.table import Table 25 26TESTTABLE = """ 27<table:table xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" /> 28""" 29def tofloats(values): 30 return [cell.value for cell in values] 31 32class TestTableAttributes(unittest.TestCase): 33 def test_has_TAG(self): 34 table = Table() 35 self.assertEqual(table.TAG, CN('table:table')) 36 37 def test_has_xmlnode(self): 38 table = Table() 39 self.assertIsNotNone(table.xmlnode) 40 41 def test_get_name(self): 42 table = Table() 43 name = table.name 44 self.assertTrue(is_string(name)) 45 46 def test_set_name(self): 47 table = Table() 48 table.name = 'TABLE' 49 self.assertEqual(table.name, 'TABLE') 50 self.assertEqual(table.get_attr(CN('table:name')), 'TABLE', 'wrong tag name') 51 52 def test_name_with_cr_and_tabs(self): 53 table = Table('table\tname\r ') 54 self.assertEqual(table.name, 'table name', "table name not normalized") 55 56 def test_name_with_apostroph(self): 57 table = Table('"table name"') 58 self.assertEqual(table.name, 'table name', "table name not normalized") 59 60 def test_name_with_apostroph2(self): 61 table = Table(" table'name") 62 self.assertEqual(table.name, 'table name', "table name not normalized") 63 64 def test_get_style_name(self): 65 table = Table() 66 self.assertIsNone(table.style_name) 67 68 def test_set_style_name(self): 69 table = Table() 70 table.style_name = 'STYLE' 71 self.assertEqual(table.style_name, 'STYLE') 72 self.assertEqual(table.get_attr(CN('table:style-name')), 'STYLE', 'wrong tag name') 73 74 def test_get_protected(self): 75 table = Table() 76 self.assertFalse(table.protected) 77 78 def test_set_protected(self): 79 table = Table() 80 table.protected = True 81 self.assertTrue(table.protected) 82 self.assertEqual(table.get_attr(CN('table:protected')), 'true', 'wrong tag name') 83 84 def test_protection_key_not_set(self): 85 table = Table() 86 key = table.get_attr(CN('table:protection-key')) 87 self.assertIsNone(key) 88 89 def test_protection_key_is_set(self): 90 table = Table() 91 table.protected = True 92 key = table.get_attr(CN('table:protection-key')) 93 self.assertIsNotNone(key, "protection-key not set") 94 self.assertGreater(len(key), 8, "protection-key is too short") 95 96 def test_get_print(self): 97 table = Table() 98 self.assertFalse(table.print_) 99 100 def test_set_print(self): 101 table = Table() 102 table.print_ = True 103 self.assertTrue(table.print_) 104 self.assertEqual(table.get_attr(CN('table:print')), 'true', 'table:print should be true') 105 106 def test_if_Table_class_is_registered(self): 107 table = wrap(etree.XML(TESTTABLE)) 108 self.assertEqual(table.TAG, CN('table:table'), 'Table class is not registered') 109 110TABLE_5x3 = """ 111<table:table xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"> 112<table:table-row><table:table-cell /><table:table-cell /><table:table-cell /></table:table-row> 113<table:table-row><table:table-cell /><table:table-cell /><table:table-cell /></table:table-row> 114<table:table-row><table:table-cell /><table:table-cell /><table:table-cell /></table:table-row> 115<table:table-row><table:table-cell /><table:table-cell /><table:table-cell /></table:table-row> 116<table:table-row><table:table-cell /><table:table-cell /><table:table-cell /></table:table-row> 117</table:table> 118""" 119 120TABLE_REP_7x7 = """ 121<table:table xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"> 122<table:table-header-rows> 123 <table:table-row><table:table-cell table:number-columns-repeated="6"/><table:table-cell /></table:table-row> 124</table:table-header-rows> 125<table:table-rows> 126 <table:table-row table:number-rows-repeated="5"><table:table-cell table:number-columns-repeated="6" /><table:table-cell /></table:table-row> 127 <table:table-row><table:table-cell table:number-columns-repeated="6"/><table:table-cell /></table:table-row> 128</table:table-rows> 129</table:table> 130""" 131 132class TestTableMethods(unittest.TestCase): 133 def test_nrows(self): 134 table = wrap(etree.XML(TABLE_5x3)) 135 self.assertEqual(table.nrows(), 5) 136 137 def test_nrows_repeated(self): 138 table = wrap(etree.XML(TABLE_REP_7x7)) 139 self.assertEqual(table.nrows(), 7) 140 141 def test_ncols(self): 142 table = wrap(etree.XML(TABLE_5x3)) 143 self.assertEqual(table.ncols(), 3) 144 145 def test_ncols_repeated(self): 146 table = wrap(etree.XML(TABLE_REP_7x7)) 147 self.assertEqual(table.ncols(), 7) 148 149 def test_init_row_cols(self): 150 table = Table(name="TEST", size=(7, 5)) 151 self.assertEqual(table.nrows(), 7) 152 self.assertEqual(table.ncols(), 5) 153 154 def test_reset(self): 155 table = Table(name="TEST", size=(7, 5)) 156 table.reset(size=(8, 10)) 157 self.assertEqual("TEST", table.name, "name attribute is deleted") 158 self.assertEqual(table.ncols(), 10) 159 self.assertEqual(table.nrows(), 8) 160 161 def test_clear_table(self): 162 table = Table(name="TEST") 163 table[0,0].set_value("marker") 164 table.clear() 165 self.assertIsNone(table[0,0].value, "cell value should be None") 166 167 def test_setup_error(self): 168 with self.assertRaises(ValueError): 169 Table(size=(1, 0)) 170 with self.assertRaises(ValueError): 171 Table(size=(0, 1)) 172 173 def test_copy_table_with_new_name(self): 174 table1 = Table(name='Test') 175 table1['A1'].set_value('marker') 176 177 table2 = table1.copy(newname='Copy of '+table1.name) 178 179 self.assertEqual('Copy of Test', table2.name, "table2 has wrong name.") 180 self.assertEqual('marker', table2['A1'].value, "marker not found in table2") 181 182 def test_copy_table_without_new_name(self): 183 table1 = Table(name='Test') 184 table2 = table1.copy() 185 self.assertEqual('CopyOfTest', table2.name, "table2 has wrong name.") 186 187TABLE_COMP = """ 188<table:table xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"> 189<table:table-row table:number-rows-repeated="6"> 190 <table:table-cell table:number-columns-repeated="6"/> 191 <table:table-cell/> 192</table:table-row> 193<table:table-row> 194 <table:table-cell table:number-columns-repeated="6"/> 195 <table:table-cell/> 196</table:table-row> 197</table:table> 198""" 199 200class TestTableContent(unittest.TestCase): 201 def setUp(self): 202 self.table = Table(xmlnode=etree.XML(TABLE_COMP)) 203 204 def test_metrics(self): 205 self.assertEqual(self.table.ncols(), 7) 206 self.assertEqual(self.table.nrows(), 7) 207 208 def test_set_get_different_values(self): 209 ncols = self.table.ncols() 210 for row in range(self.table.nrows()): 211 for col in range(ncols): 212 cell = self.table[row, col] 213 cell.set_value(row*ncols + col, 'float') 214 215 for row in range(self.table.nrows()): 216 for col in range(ncols): 217 cell = self.table[row, col] 218 self.assertEqual(row*ncols + col, int(cell.value)) 219 220 221SQUAREMATRIX = """ 222<table:table 223 xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 224 xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 225 xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 226 table:name="RowColAccess"> 227 228<table:table-columns> 229 <table:table-column table:style-name="c0" /> 230 <table:table-column table:style-name="c1" /> 231 <table:table-column table:style-name="c2" /> 232 <table:table-column table:style-name="c3" /> 233</table:table-columns> 234 235<table:table-rows> 236 <table:table-row table:style-name='r0'> 237 <table:table-cell office:value-type="float" office:value="1" /> 238 <table:table-cell office:value-type="float" office:value="2" /> 239 <table:table-cell office:value-type="float" office:value="3" /> 240 <table:table-cell office:value-type="float" office:value="4" /> 241 </table:table-row> 242 <table:table-row table:style-name='r1'> 243 <table:table-cell office:value-type="float" office:value="5" /> 244 <table:table-cell office:value-type="float" office:value="6" /> 245 <table:table-cell office:value-type="float" office:value="7" /> 246 <table:table-cell office:value-type="float" office:value="8" /> 247 </table:table-row> 248 <table:table-row table:style-name='r2'> 249 <table:table-cell office:value-type="float" office:value="9" /> 250 <table:table-cell office:value-type="float" office:value="10" /> 251 <table:table-cell office:value-type="float" office:value="11" /> 252 <table:table-cell office:value-type="float" office:value="12" /> 253 </table:table-row> 254 <table:table-row table:style-name='r3'> 255 <table:table-cell office:value-type="float" office:value="13" /> 256 <table:table-cell office:value-type="float" office:value="14" /> 257 <table:table-cell office:value-type="float" office:value="15" /> 258 <table:table-cell office:value-type="float" office:value="16" /> 259 </table:table-row> 260</table:table-rows> 261</table:table> 262""" 263 264class TestTableContentAccess(unittest.TestCase): 265 def setUp(self): 266 self.table = Table(xmlnode=etree.XML(SQUAREMATRIX)) 267 268 def test_metrics(self): 269 self.assertEqual(self.table.name, 'RowColAccess') 270 self.assertEqual(self.table.ncols(), 4) 271 self.assertEqual(self.table.nrows(), 4) 272 273 def test_row_neg_index(self): 274 cell = self.table[-1, 0] 275 self.assertEqual(cell.value, 13.) 276 277 def test_col_index_error(self): 278 with self.assertRaises(IndexError): 279 self.table[0, 4] 280 281 def test_access_cell_by_index(self): 282 cell = self.table[0, 0] 283 self.assertEqual(cell.value, 1.) 284 285 def test_access_cell_by_reference(self): 286 cell = self.table['B1'] 287 self.assertEqual(cell.value, 2.) 288 289 def test_setting_cell_by_index(self): 290 self.table[0, 0] = Cell('Textcell') 291 cell = self.table['A1'] 292 self.assertEqual(cell.plaintext(), "Textcell") 293 294 def test_setting_cell_by_address(self): 295 self.table['A1'] = Cell('Textcell') 296 cell = self.table[0, 0] 297 self.assertEqual(cell.plaintext(), "Textcell") 298 299 def test_set_cell_row_index_error(self): 300 with self.assertRaises(IndexError): 301 self.table[10, 0] = Cell() 302 303 def test_set_cell_column_index_error(self): 304 with self.assertRaises(IndexError): 305 self.table[0, 10] = Cell() 306 307 def test_set_cell_neg_row_index(self): 308 self.table[-1, 0] = Cell('Textcell') 309 cell = self.table[3, 0] 310 self.assertEqual(cell.plaintext(), "Textcell") 311 312 def test_set_cell_neg_column_index(self): 313 self.table[0, -1] = Cell('Textcell') 314 cell = self.table[0, 3] 315 self.assertEqual(cell.plaintext(), "Textcell") 316 317 def test_if_rows_generates_lists(self): 318 nrows = self.table.nrows() 319 ncols = self.table.ncols() 320 for row in self.table.rows(): 321 cells = row 322 self.assertEqual(len(cells), ncols) 323 324class TestRowColumnAccess(unittest.TestCase): 325 def setUp(self): 326 self.table = Table(xmlnode=etree.XML(SQUAREMATRIX)) 327 328 def test_get_row_1_by_index(self): 329 values = [cell.value for cell in self.table.row(1)] 330 self.assertEqual(values, [5., 6., 7., 8.]) 331 332 def test_get_row_1_by_address(self): 333 self.assertEqual(tofloats(self.table.row('A2')), [5., 6., 7., 8.]) 334 335 def test_row_slice(self): 336 self.assertEqual(tofloats(self.table.row(1)[1:3]), [6., 7.]) 337 338 def test_row_index_error(self): 339 with self.assertRaises(IndexError): 340 self.table.row(4) 341 342 def test_row_neg_index(self): 343 self.assertEqual(tofloats(self.table.row(-1)), [13., 14., 15., 16.]) 344 345 def test_get_column_1_by_index(self): 346 self.assertEqual(tofloats(self.table.column(1)), [2., 6., 10., 14.]) 347 348 def test_get_column_1_by_address(self): 349 self.assertEqual(tofloats(self.table.column('B2')), [2., 6., 10., 14.]) 350 351 def test_column_slice(self): 352 self.assertEqual(tofloats(self.table.column(1)[1:3]), [6., 10.]) 353 354 def test_column_index_error(self): 355 with self.assertRaises(IndexError): 356 self.table.column(4) 357 358 def test_column_neg_index(self): 359 self.assertEqual(tofloats(self.table.column(-1)), [4., 8., 12., 16.]) 360 361 def test_rows(self): 362 values = tofloats(chain(*self.table.rows())) 363 expected = [float(x) for x in range(1, 17)] 364 self.assertEqual(expected, values) 365 366 def test_columns(self): 367 values = tofloats(chain(*self.table.columns())) 368 expected = [1., 5., 9., 13., 2., 6., 10., 14., 3., 7., 11., 15., 4., 8., 12., 16.] 369 self.assertEqual(expected, values) 370 371class TestRowColumnInfoAccess(unittest.TestCase): 372 def setUp(self): 373 self.table = Table(xmlnode=etree.XML(SQUAREMATRIX)) 374 375 def test_get_row_info(self): 376 row_info = self.table.row_info(0) 377 self.assertEqual(row_info.style_name, 'r0') 378 379 def test_get_row_info_by_address(self): 380 row_info = self.table.row_info('C2') 381 self.assertEqual(row_info.style_name, 'r1') 382 383 def test_get_row_info_neg_index(self): 384 row_info = self.table.row_info(-1) 385 self.assertEqual(row_info.style_name, 'r3') 386 387 def test_get_row_info_index_error(self): 388 with self.assertRaises(IndexError): 389 self.table.row_info(4) 390 391 def test_get_column_info(self): 392 column_info = self.table.column_info(0) 393 self.assertEqual(column_info.style_name, 'c0') 394 395 def test_get_column_info_by_address(self): 396 column_info = self.table.column_info('B3') 397 self.assertEqual(column_info.style_name, 'c1') 398 399 def test_get_column_info_neg_index(self): 400 column_info = self.table.column_info(-1) 401 self.assertEqual(column_info.style_name, 'c3') 402 403 def test_get_column_info_index_error(self): 404 with self.assertRaises(IndexError): 405 self.table.column_info(4) 406 407class TestCellSpan(unittest.TestCase): 408 # this test-case tests only, if cell spanning is available 409 # for extensive cell span testing see: test_cell_span_controller.py 410 def setUp(self): 411 self.table = Table(name="TEST", size=(10, 10)) 412 413 def test_set_cell_span(self): 414 self.table.set_cell_span('A1', (3, 3)) 415 self.assertEqual((3, 3), self.table['A1'].span, "Span values for cell 'A1' not set.") 416 self.assertTrue(self.table['B2'].covered, "cell 'B1' is not covered") 417 418 def test_remove_cell_span(self): 419 self.table.set_cell_span('A1', (3, 3)) 420 self.table.remove_cell_span('A1') 421 self.assertEqual((1, 1), self.table['A1'].span, "Span values for cell 'A1' should be (1, 1).") 422 self.assertFalse(self.table['B2'].covered, "cell 'B1' is covered") 423 424 425if __name__=='__main__': 426 unittest.main() 427