Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/cc_modules/tests/cc_tsv_tests.py 

5 

6=============================================================================== 

7 

8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com). 

9 

10 This file is part of CamCOPS. 

11 

12 CamCOPS is free software: you can redistribute it and/or modify 

13 it under the terms of the GNU General Public License as published by 

14 the Free Software Foundation, either version 3 of the License, or 

15 (at your option) any later version. 

16 

17 CamCOPS is distributed in the hope that it will be useful, 

18 but WITHOUT ANY WARRANTY; without even the implied warranty of 

19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

20 GNU General Public License for more details. 

21 

22 You should have received a copy of the GNU General Public License 

23 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

24 

25=============================================================================== 

26 

27""" 

28 

29import io 

30from typing import Any, Dict 

31from unittest import TestCase 

32import uuid 

33from xml.dom.minidom import parseString 

34import zipfile 

35 

36from camcops_server.cc_modules.cc_tsv import ( 

37 ODS_VIA_PYEXCEL, 

38 TsvCollection, 

39 TsvPage, 

40 XLSX_VIA_PYEXCEL, 

41) 

42 

43if ODS_VIA_PYEXCEL: 

44 import pyexcel_ods3 # e.g. pip install pyexcel-ods3==0.5.3 

45 ODSWriter = ODSSheet = None 

46else: 

47 from odswriter import ODSWriter, Sheet as ODSSheet # noqa 

48 pyexcel_ods3 = None 

49 

50if XLSX_VIA_PYEXCEL: 

51 import pyexcel_xlsx # e.g. pip install pyexcel-xlsx==0.5.7 

52 openpyxl = XLWorkbook = XLWorksheet = None 

53else: 

54 from openpyxl.workbook.workbook import Workbook as XLWorkbook 

55 pyexcel_xlsx = None 

56 

57 

58# ============================================================================= 

59# Unit tests 

60# ============================================================================= 

61 

62class TsvCollectionTests(TestCase): 

63 def test_xlsx_created_from_zero_rows(self) -> None: 

64 page = TsvPage(name="test", rows=[]) 

65 coll = TsvCollection() 

66 coll.add_page(page) 

67 

68 output = coll.as_xlsx() 

69 

70 # https://en.wikipedia.org/wiki/List_of_file_signatures 

71 self.assertEqual(output[0], 0x50) 

72 self.assertEqual(output[1], 0x4B) 

73 self.assertEqual(output[2], 0x03) 

74 self.assertEqual(output[3], 0x04) 

75 

76 def test_xlsx_worksheet_names_are_page_names(self) -> None: 

77 page1 = TsvPage(name="name 1", 

78 rows=[{"test data 1": "row 1"}]) 

79 page2 = TsvPage(name="name 2", 

80 rows=[{"test data 2": "row 1"}]) 

81 page3 = TsvPage(name="name 3", 

82 rows=[{"test data 3": "row 1"}]) 

83 coll = TsvCollection() 

84 

85 coll.add_pages([page1, page2, page3]) 

86 

87 data = coll.as_xlsx() 

88 buffer = io.BytesIO(data) 

89 expected_sheetnames = ["name 1", "name 2", "name 3"] 

90 if openpyxl: 

91 wb = openpyxl.load_workbook(buffer) # type: XLWorkbook 

92 self.assertEqual(wb.sheetnames, expected_sheetnames) 

93 else: 

94 wb = pyexcel_xlsx.get_data(buffer) # type: Dict[str, Any] 

95 sheetnames = list(wb.keys()) 

96 self.assertEqual(sheetnames, expected_sheetnames) 

97 

98 def test_xlsx_page_name_exactly_31_chars_not_truncated(self) -> None: 

99 page = TsvPage(name="abcdefghijklmnopqrstuvwxyz78901", 

100 rows=[{"test data 1": "row 1"}]) 

101 coll = TsvCollection() 

102 

103 self.assertEqual( 

104 coll.get_sheet_title(page), 

105 "abcdefghijklmnopqrstuvwxyz78901" 

106 ) 

107 

108 def test_xlsx_page_name_over_31_chars_truncated(self) -> None: 

109 page = TsvPage(name="abcdefghijklmnopqrstuvwxyz78901234", 

110 rows=[{"test data 1": "row 1"}]) 

111 coll = TsvCollection() 

112 

113 self.assertEqual( 

114 coll.get_sheet_title(page), 

115 "abcdefghijklmnopqrstuvwxyz78..." 

116 ) 

117 

118 def test_xlsx_invalid_chars_in_page_name_replaced(self) -> None: 

119 page = TsvPage(name="[a]b\\c:d/e*f?g'h", 

120 rows=[{"test data 1": "row 1"}]) 

121 coll = TsvCollection() 

122 

123 self.assertEqual( 

124 coll.get_sheet_title(page), 

125 "_a_b_c_d_e_f_g_h" 

126 ) 

127 

128 def test_ods_page_name_sanitised(self) -> None: 

129 # noinspection PyUnresolvedReferences 

130 page = TsvPage(name="What perinatal service have you accessed?", 

131 rows=[{"test data 1": "row 1"}]) 

132 coll = TsvCollection() 

133 coll.add_pages([page]) 

134 

135 data = coll.as_ods() 

136 

137 zf = zipfile.ZipFile(io.BytesIO(data), "r") 

138 content = zf.read('content.xml') 

139 doc = parseString(content) 

140 sheets = doc.getElementsByTagName('table:table') 

141 self.assertEqual(sheets[0].getAttribute("table:name"), 

142 "What perinatal service have ...") 

143 

144 def test_worksheet_names_are_not_duplicated(self) -> None: 

145 page1 = TsvPage(name="abcdefghijklmnopqrstuvwxyz78901234", 

146 rows=[{"test data 1": "row 1"}]) 

147 page2 = TsvPage(name="ABCDEFGHIJKLMNOPQRSTUVWXYZ789012345", 

148 rows=[{"test data 2": "row 1"}]) 

149 page3 = TsvPage(name="abcdefghijklmnopqrstuvwxyz7890123456", 

150 rows=[{"test data 3": "row 1"}]) 

151 coll = TsvCollection() 

152 

153 coll.add_pages([page1, page2, page3]) 

154 

155 valid_sheet_names = coll.get_pages_with_valid_sheet_names() 

156 

157 names = [v for k, v in valid_sheet_names.items()] 

158 

159 self.assertIn("abcdefghijklmnopqrstuvwxyz78...", names) 

160 self.assertIn("ABCDEFGHIJKLMNOPQRSTUVWXYZ78..1", names) 

161 self.assertIn("abcdefghijklmnopqrstuvwxyz78..2", names) 

162 

163 def test_uuid_exported_to_ods_as_string(self) -> None: 

164 test_uuid = uuid.UUID("6457cb90-1ca0-47a7-9f40-767567819bee") 

165 

166 page = TsvPage(name="Testing", 

167 rows=[{"UUID": test_uuid}]) 

168 coll = TsvCollection() 

169 coll.add_pages([page]) 

170 

171 data = coll.as_ods() 

172 zf = zipfile.ZipFile(io.BytesIO(data), "r") 

173 content = zf.read('content.xml') 

174 doc = parseString(content) 

175 text_values = [t.firstChild.nodeValue 

176 for t in doc.getElementsByTagName("text:p")] 

177 

178 self.assertIn("UUID", text_values) 

179 self.assertIn("6457cb90-1ca0-47a7-9f40-767567819bee", text_values) 

180 

181 def test_uuid_exported_to_xlsx_as_string(self) -> None: 

182 test_uuid = uuid.UUID("6457cb90-1ca0-47a7-9f40-767567819bee") 

183 

184 page = TsvPage(name="Testing", 

185 rows=[{"UUID": test_uuid}]) 

186 coll = TsvCollection() 

187 coll.add_pages([page]) 

188 

189 data = coll.as_xlsx() 

190 buffer = io.BytesIO(data) 

191 if openpyxl: 

192 self.fail("This test has not been written for openpyxl") 

193 else: 

194 wb = pyexcel_xlsx.get_data(buffer) # type: Dict[str, Any] 

195 self.assertIn(["UUID"], wb["Testing"]) 

196 self.assertIn(["6457cb90-1ca0-47a7-9f40-767567819bee"], 

197 wb["Testing"])