Coverage for cc_modules/tests/cc_spreadsheet_tests.py: 22%

96 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-08 23:14 +0000

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/cc_modules/tests/cc_spreadsheet_tests.py 

5 

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

7 

8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry. 

9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk). 

10 

11 This file is part of CamCOPS. 

12 

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

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

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

16 (at your option) any later version. 

17 

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

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

20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

21 GNU General Public License for more details. 

22 

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

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

25 

26=============================================================================== 

27 

28""" 

29 

30import io 

31from typing import Any, Dict 

32from unittest import TestCase 

33import uuid 

34from xml.dom.minidom import parseString 

35import zipfile 

36 

37from camcops_server.cc_modules.cc_spreadsheet import ( 

38 SpreadsheetCollection, 

39 SpreadsheetPage, 

40 XLSX_VIA_PYEXCEL, 

41) 

42 

43if XLSX_VIA_PYEXCEL: 

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

45 

46 openpyxl = XLWorkbook = XLWorksheet = None 

47else: 

48 import openpyxl 

49 from openpyxl.workbook.workbook import Workbook as XLWorkbook 

50 

51 pyexcel_xlsx = None 

52 

53 

54# ============================================================================= 

55# Unit tests 

56# ============================================================================= 

57 

58 

59class SpreadsheetCollectionTests(TestCase): 

60 def test_xlsx_created_from_zero_rows(self) -> None: 

61 page = SpreadsheetPage(name="test", rows=[]) 

62 coll = SpreadsheetCollection() 

63 coll.add_page(page) 

64 

65 output = coll.as_xlsx() 

66 

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

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

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

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

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

72 

73 def test_xlsx_worksheet_names_are_page_names(self) -> None: 

74 page1 = SpreadsheetPage(name="name 1", rows=[{"test data 1": "row 1"}]) 

75 page2 = SpreadsheetPage(name="name 2", rows=[{"test data 2": "row 1"}]) 

76 page3 = SpreadsheetPage(name="name 3", rows=[{"test data 3": "row 1"}]) 

77 coll = SpreadsheetCollection() 

78 

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

80 

81 data = coll.as_xlsx() 

82 buffer = io.BytesIO(data) 

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

84 if openpyxl: 

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

86 self.assertEqual(wb.sheetnames, expected_sheetnames) 

87 else: 

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

89 sheetnames = list(wb.keys()) 

90 self.assertEqual(sheetnames, expected_sheetnames) 

91 

92 def test_xlsx_page_name_exactly_31_chars_not_truncated(self) -> None: 

93 page = SpreadsheetPage( 

94 name="abcdefghijklmnopqrstuvwxyz78901", 

95 rows=[{"test data 1": "row 1"}], 

96 ) 

97 coll = SpreadsheetCollection() 

98 

99 self.assertEqual( 

100 coll.get_sheet_title(page), "abcdefghijklmnopqrstuvwxyz78901" 

101 ) 

102 

103 def test_xlsx_page_name_over_31_chars_truncated(self) -> None: 

104 page = SpreadsheetPage( 

105 name="abcdefghijklmnopqrstuvwxyz78901234", 

106 rows=[{"test data 1": "row 1"}], 

107 ) 

108 coll = SpreadsheetCollection() 

109 

110 self.assertEqual( 

111 coll.get_sheet_title(page), "abcdefghijklmnopqrstuvwxyz78..." 

112 ) 

113 

114 def test_xlsx_invalid_chars_in_page_name_replaced(self) -> None: 

115 page = SpreadsheetPage( 

116 name="[a]b\\c:d/e*f?g'h", rows=[{"test data 1": "row 1"}] 

117 ) 

118 coll = SpreadsheetCollection() 

119 

120 self.assertEqual(coll.get_sheet_title(page), "_a_b_c_d_e_f_g_h") 

121 

122 def test_ods_page_name_sanitised(self) -> None: 

123 # noinspection PyUnresolvedReferences 

124 page = SpreadsheetPage( 

125 name="What perinatal service have you accessed?", 

126 rows=[{"test data 1": "row 1"}], 

127 ) 

128 coll = SpreadsheetCollection() 

129 coll.add_pages([page]) 

130 

131 data = coll.as_ods() 

132 

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

134 content = zf.read("content.xml") 

135 doc = parseString(content) 

136 sheets = doc.getElementsByTagName("table:table") 

137 self.assertEqual( 

138 sheets[0].getAttribute("table:name"), 

139 "What perinatal service have ...", 

140 ) 

141 

142 def test_worksheet_names_are_not_duplicated(self) -> None: 

143 page1 = SpreadsheetPage( 

144 name="abcdefghijklmnopqrstuvwxyz78901234", 

145 rows=[{"test data 1": "row 1"}], 

146 ) 

147 page2 = SpreadsheetPage( 

148 name="ABCDEFGHIJKLMNOPQRSTUVWXYZ789012345", 

149 rows=[{"test data 2": "row 1"}], 

150 ) 

151 page3 = SpreadsheetPage( 

152 name="abcdefghijklmnopqrstuvwxyz7890123456", 

153 rows=[{"test data 3": "row 1"}], 

154 ) 

155 coll = SpreadsheetCollection() 

156 

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

158 

159 valid_sheet_names = coll.get_pages_with_valid_sheet_names() 

160 

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

162 

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

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

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

166 

167 def test_uuid_exported_to_ods_as_string(self) -> None: 

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

169 

170 page = SpreadsheetPage(name="Testing", rows=[{"UUID": test_uuid}]) 

171 coll = SpreadsheetCollection() 

172 coll.add_pages([page]) 

173 

174 data = coll.as_ods() 

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

176 content = zf.read("content.xml") 

177 doc = parseString(content) 

178 text_values = [ 

179 t.firstChild.nodeValue for t in doc.getElementsByTagName("text:p") 

180 ] 

181 

182 self.assertIn("UUID", text_values) 

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

184 

185 def test_uuid_exported_to_xlsx_as_string(self) -> None: 

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

187 

188 page = SpreadsheetPage(name="Testing", rows=[{"UUID": test_uuid}]) 

189 coll = SpreadsheetCollection() 

190 coll.add_pages([page]) 

191 

192 data = coll.as_xlsx() 

193 buffer = io.BytesIO(data) 

194 if openpyxl: 

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

196 else: 

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

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

199 self.assertIn( 

200 ["6457cb90-1ca0-47a7-9f40-767567819bee"], wb["Testing"] 

201 )