lib_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. package xlsx
  2. import (
  3. "bytes"
  4. "encoding/xml"
  5. "fmt"
  6. "strconv"
  7. "strings"
  8. "testing"
  9. )
  10. // Test we can correctly open a XSLX file and return a xlsx.File
  11. // struct.
  12. func TestOpenFile(t *testing.T) {
  13. var xlsxFile *File
  14. var error error
  15. xlsxFile, error = OpenFile("testfile.xlsx")
  16. if error != nil {
  17. t.Error(error.Error())
  18. return
  19. }
  20. if xlsxFile == nil {
  21. t.Error("OpenFile returned nil FileInterface without generating an os.Error")
  22. return
  23. }
  24. }
  25. // Test that when we open a real XLSX file we create xlsx.Sheet
  26. // objects for the sheets inside the file and that these sheets are
  27. // themselves correct.
  28. func TestCreateSheet(t *testing.T) {
  29. var xlsxFile *File
  30. var error error
  31. var sheet *Sheet
  32. var row *Row
  33. xlsxFile, error = OpenFile("testfile.xlsx")
  34. if error != nil {
  35. t.Error(error.Error())
  36. return
  37. }
  38. if xlsxFile == nil {
  39. t.Error("OpenFile returned a nil File pointer but did not generate an error.")
  40. return
  41. }
  42. sheetLen := len(xlsxFile.Sheets)
  43. if sheetLen == 0 {
  44. t.Error("Expected len(xlsxFile.Sheets) > 0, but got ", sheetLen)
  45. return
  46. }
  47. sheet = xlsxFile.Sheets[0]
  48. rowLen := len(sheet.Rows)
  49. if rowLen != 2 {
  50. t.Error("Expected len(sheet.Rows) == 2, but got ", rowLen)
  51. return
  52. }
  53. row = sheet.Rows[0]
  54. if len(row.Cells) != 2 {
  55. t.Error("Expected len(row.Cells) == 2")
  56. return
  57. }
  58. cell := row.Cells[0]
  59. cellstring := cell.String()
  60. if cellstring != "Foo" {
  61. t.Error("Expected cell.String() == 'Foo', got ", cellstring)
  62. }
  63. }
  64. // Test that we can correctly extract a reference table from the
  65. // sharedStrings.xml file embedded in the XLSX file and return a
  66. // reference table of string values from it.
  67. func TestReadSharedStringsFromZipFile(t *testing.T) {
  68. var xlsxFile *File
  69. var error error
  70. xlsxFile, error = OpenFile("testfile.xlsx")
  71. if error != nil {
  72. t.Error(error.Error())
  73. return
  74. }
  75. if xlsxFile.referenceTable == nil {
  76. t.Error("expected non nil xlsxFile.referenceTable")
  77. return
  78. }
  79. }
  80. // We can correctly extract a style table from the style.xml file
  81. // embedded in the XLSX file and return a styles struct from it.
  82. func TestReadStylesFromZipFile(t *testing.T) {
  83. var xlsxFile *File
  84. var error error
  85. var fontCount, fillCount int
  86. var font xlsxFont
  87. var fill xlsxFill
  88. xlsxFile, error = OpenFile("testfile.xlsx")
  89. if error != nil {
  90. t.Error(error.Error())
  91. return
  92. }
  93. if xlsxFile.styles == nil {
  94. t.Error("expected non nil xlsxFile.styles")
  95. return
  96. }
  97. fontCount = len(xlsxFile.styles.Fonts)
  98. if fontCount != 4 {
  99. t.Error("expected exactly 4 xslxFonts, got ", fontCount)
  100. return
  101. }
  102. font = xlsxFile.styles.Fonts[0]
  103. if font.Sz.Val != "11" {
  104. t.Error("expected font.Sz.Val == 11, got ", font.Sz.Val)
  105. return
  106. }
  107. if font.Name.Val != "Calibri" {
  108. t.Error("expected font.Name.Val == 'Calibri', got ", font.Name.Val)
  109. return
  110. }
  111. fillCount = len(xlsxFile.styles.Fills)
  112. if fillCount != 3 {
  113. t.Error("Expected exactly 3 xlsxFills, got ", fillCount)
  114. return
  115. }
  116. fill = xlsxFile.styles.Fills[0]
  117. fmt.Printf("%v\n", fill)
  118. fill = xlsxFile.styles.Fills[1]
  119. fmt.Printf("%v\n", fill)
  120. fill = xlsxFile.styles.Fills[2]
  121. fmt.Printf("%v\n", fill)
  122. }
  123. func TestLettersToNumeric(t *testing.T) {
  124. cases := map[string]int{"A": 0, "G": 6, "z": 25, "AA": 26, "Az": 51,
  125. "BA": 52, "Bz": 77, "ZA": 26*26 + 0, "ZZ": 26*26 + 25,
  126. "AAA": 26*26 + 26 + 0, "AMI": 1022}
  127. for input, ans := range cases {
  128. output := lettersToNumeric(input)
  129. if output != ans {
  130. t.Error("Expected output '"+input+"' == ", ans,
  131. "but got ", strconv.Itoa(output))
  132. }
  133. }
  134. }
  135. func TestLetterOnlyMapFunction(t *testing.T) {
  136. var input string = "ABC123"
  137. var output string = strings.Map(letterOnlyMapF, input)
  138. if output != "ABC" {
  139. t.Error("Expected output == 'ABC' but got ", output)
  140. }
  141. input = "abc123"
  142. output = strings.Map(letterOnlyMapF, input)
  143. if output != "ABC" {
  144. t.Error("Expected output == 'ABC' but got ", output)
  145. }
  146. }
  147. func TestIntOnlyMapFunction(t *testing.T) {
  148. var input string = "ABC123"
  149. var output string = strings.Map(intOnlyMapF, input)
  150. if output != "123" {
  151. t.Error("Expected output == '123' but got ", output)
  152. }
  153. }
  154. func TestGetCoordsFromCellIDString(t *testing.T) {
  155. var cellIDString string = "A3"
  156. var x, y int
  157. var error error
  158. x, y, error = getCoordsFromCellIDString(cellIDString)
  159. if error != nil {
  160. t.Error(error)
  161. }
  162. if x != 0 {
  163. t.Error("Expected x == 0, but got ", strconv.Itoa(x))
  164. }
  165. if y != 2 {
  166. t.Error("Expected y == 2, but got ", strconv.Itoa(y))
  167. }
  168. }
  169. func TestGetRangeFromString(t *testing.T) {
  170. var rangeString string
  171. var lower, upper int
  172. var error error
  173. rangeString = "1:3"
  174. lower, upper, error = getRangeFromString(rangeString)
  175. if error != nil {
  176. t.Error(error)
  177. }
  178. if lower != 1 {
  179. t.Error("Expected lower bound == 1, but got ", strconv.Itoa(lower))
  180. }
  181. if upper != 3 {
  182. t.Error("Expected upper bound == 3, but got ", strconv.Itoa(upper))
  183. }
  184. }
  185. func TestMakeRowFromSpan(t *testing.T) {
  186. var rangeString string
  187. var row *Row
  188. var length int
  189. rangeString = "1:3"
  190. row = makeRowFromSpan(rangeString)
  191. length = len(row.Cells)
  192. if length != 3 {
  193. t.Error("Expected a row with 3 cells, but got ", strconv.Itoa(length))
  194. }
  195. rangeString = "5:7" // Note - we ignore lower bound!
  196. row = makeRowFromSpan(rangeString)
  197. length = len(row.Cells)
  198. if length != 7 {
  199. t.Error("Expected a row with 7 cells, but got ", strconv.Itoa(length))
  200. }
  201. rangeString = "1:1"
  202. row = makeRowFromSpan(rangeString)
  203. length = len(row.Cells)
  204. if length != 1 {
  205. t.Error("Expected a row with 1 cells, but got ", strconv.Itoa(length))
  206. }
  207. }
  208. func TestReadRowsFromSheet(t *testing.T) {
  209. var sharedstringsXML = bytes.NewBufferString(`
  210. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  211. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="4" uniqueCount="4">
  212. <si>
  213. <t>Foo</t>
  214. </si>
  215. <si>
  216. <t>Bar</t>
  217. </si>
  218. <si>
  219. <t xml:space="preserve">Baz </t>
  220. </si>
  221. <si>
  222. <t>Quuk</t>
  223. </si>
  224. </sst>`)
  225. var sheetxml = bytes.NewBufferString(`
  226. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  227. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  228. xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  229. <dimension ref="A1:B2"/>
  230. <sheetViews>
  231. <sheetView tabSelected="1" workbookViewId="0">
  232. <selection activeCell="C2" sqref="C2"/>
  233. </sheetView>
  234. </sheetViews>
  235. <sheetFormatPr baseColWidth="10" defaultRowHeight="15"/>
  236. <sheetData>
  237. <row r="1" spans="1:2">
  238. <c r="A1" t="s">
  239. <v>0</v>
  240. </c>
  241. <c r="B1" t="s">
  242. <v>1</v>
  243. </c>
  244. </row>
  245. <row r="2" spans="1:2">
  246. <c r="A2" t="s">
  247. <v>2</v>
  248. </c>
  249. <c r="B2" t="s">
  250. <v>3</v>
  251. </c>
  252. </row>
  253. </sheetData>
  254. <pageMargins left="0.7" right="0.7"
  255. top="0.78740157499999996"
  256. bottom="0.78740157499999996"
  257. header="0.3"
  258. footer="0.3"/>
  259. </worksheet>`)
  260. worksheet := new(xlsxWorksheet)
  261. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  262. if error != nil {
  263. t.Error(error.Error())
  264. return
  265. }
  266. sst := new(xlsxSST)
  267. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  268. if error != nil {
  269. t.Error(error.Error())
  270. return
  271. }
  272. file := new(File)
  273. file.referenceTable = MakeSharedStringRefTable(sst)
  274. rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
  275. if maxRows != 2 {
  276. t.Error("Expected maxRows == 2")
  277. }
  278. if maxCols != 2 {
  279. t.Error("Expected maxCols == 2")
  280. }
  281. row := rows[0]
  282. if len(row.Cells) != 2 {
  283. t.Error("Expected len(row.Cells) == 2, got ", strconv.Itoa(len(row.Cells)))
  284. }
  285. cell1 := row.Cells[0]
  286. if cell1.String() != "Foo" {
  287. t.Error("Expected cell1.String() == 'Foo', got ", cell1.String())
  288. }
  289. cell2 := row.Cells[1]
  290. if cell2.String() != "Bar" {
  291. t.Error("Expected cell2.String() == 'Bar', got ", cell2.String())
  292. }
  293. }
  294. func TestReadRowsFromSheetWithEmptyCells(t *testing.T) {
  295. var sharedstringsXML = bytes.NewBufferString(`
  296. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  297. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="8" uniqueCount="5"><si><t>Bob</t></si><si><t>Alice</t></si><si><t>Sue</t></si><si><t>Yes</t></si><si><t>No</t></si></sst>`)
  298. var sheetxml = bytes.NewBufferString(`
  299. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  300. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1:C3"/><sheetViews><sheetView tabSelected="1" workbookViewId="0"><selection activeCell="D3" sqref="D3"/></sheetView></sheetViews><sheetFormatPr baseColWidth="10" defaultRowHeight="15"/>
  301. <sheetData>
  302. <row r="1" spans="1:3">
  303. <c r="A1" t="s">
  304. <v>
  305. 0
  306. </v>
  307. </c>
  308. <c r="B1" t="s">
  309. <v>
  310. 1
  311. </v>
  312. </c>
  313. <c r="C1" t="s">
  314. <v>
  315. 2
  316. </v>
  317. </c>
  318. </row>
  319. <row r="2" spans="1:3">
  320. <c r="A2" t="s">
  321. <v>
  322. 3
  323. </v>
  324. </c>
  325. <c r="B2" t="s">
  326. <v>
  327. 4
  328. </v>
  329. </c>
  330. <c r="C2" t="s">
  331. <v>
  332. 3
  333. </v>
  334. </c>
  335. </row>
  336. <row r="3" spans="1:3">
  337. <c r="A3" t="s">
  338. <v>
  339. 4
  340. </v>
  341. </c>
  342. <c r="C3" t="s">
  343. <v>
  344. 3
  345. </v>
  346. </c>
  347. </row>
  348. </sheetData>
  349. <pageMargins left="0.7" right="0.7" top="0.78740157499999996" bottom="0.78740157499999996" header="0.3" footer="0.3"/>
  350. </worksheet>
  351. `)
  352. worksheet := new(xlsxWorksheet)
  353. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  354. if error != nil {
  355. t.Error(error.Error())
  356. return
  357. }
  358. sst := new(xlsxSST)
  359. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  360. if error != nil {
  361. t.Error(error.Error())
  362. return
  363. }
  364. file := new(File)
  365. file.referenceTable = MakeSharedStringRefTable(sst)
  366. rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
  367. if maxRows != 3 {
  368. t.Error("Expected maxRows == 3, got ", strconv.Itoa(len(rows)))
  369. }
  370. if maxCols != 3 {
  371. t.Error("Expected maxCols == 3, got ", strconv.Itoa(maxCols))
  372. }
  373. row := rows[2]
  374. if len(row.Cells) != 3 {
  375. t.Error("Expected len(row.Cells) == 3, got ", strconv.Itoa(len(row.Cells)))
  376. }
  377. cell1 := row.Cells[0]
  378. if cell1.String() != "No" {
  379. t.Error("Expected cell1.String() == 'No', got ", cell1.String())
  380. }
  381. cell2 := row.Cells[1]
  382. if cell2.String() != "" {
  383. t.Error("Expected cell2.String() == '', got ", cell2.String())
  384. }
  385. cell3 := row.Cells[2]
  386. if cell3.String() != "Yes" {
  387. t.Error("Expected cell3.String() == 'Yes', got ", cell3.String())
  388. }
  389. }
  390. func TestReadRowsFromSheetWithTrailingEmptyCells(t *testing.T) {
  391. var row *Row
  392. var cell1, cell2, cell3, cell4 *Cell
  393. var sharedstringsXML = bytes.NewBufferString(`
  394. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  395. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="4" uniqueCount="4"><si><t>A</t></si><si><t>B</t></si><si><t>C</t></si><si><t>D</t></si></sst>`)
  396. var sheetxml = bytes.NewBufferString(`
  397. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  398. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1:D8"/><sheetViews><sheetView tabSelected="1" workbookViewId="0"><selection activeCell="A7" sqref="A7"/></sheetView></sheetViews><sheetFormatPr baseColWidth="10" defaultRowHeight="15"/><sheetData><row r="1" spans="1:4"><c r="A1" t="s"><v>0</v></c><c r="B1" t="s"><v>1</v></c><c r="C1" t="s"><v>2</v></c><c r="D1" t="s"><v>3</v></c></row><row r="2" spans="1:4"><c r="A2"><v>1</v></c></row><row r="3" spans="1:4"><c r="B3"><v>1</v></c></row><row r="4" spans="1:4"><c r="C4"><v>1</v></c></row><row r="5" spans="1:4"><c r="D5"><v>1</v></c></row><row r="6" spans="1:4"><c r="C6"><v>1</v></c></row><row r="7" spans="1:4"><c r="B7"><v>1</v></c></row><row r="8" spans="1:4"><c r="A8"><v>1</v></c></row></sheetData><pageMargins left="0.7" right="0.7" top="0.78740157499999996" bottom="0.78740157499999996" header="0.3" footer="0.3"/></worksheet>
  399. `)
  400. worksheet := new(xlsxWorksheet)
  401. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  402. if error != nil {
  403. t.Error(error.Error())
  404. return
  405. }
  406. sst := new(xlsxSST)
  407. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  408. if error != nil {
  409. t.Error(error.Error())
  410. return
  411. }
  412. file := new(File)
  413. file.referenceTable = MakeSharedStringRefTable(sst)
  414. rows, maxCol, maxRow := readRowsFromSheet(worksheet, file)
  415. if maxCol != 4 {
  416. t.Error("Expected maxCol == 4, got ", strconv.Itoa(maxCol))
  417. }
  418. if maxRow != 8 {
  419. t.Error("Expected maxRow == 8, got ", strconv.Itoa(maxRow))
  420. }
  421. row = rows[0]
  422. if len(row.Cells) != 4 {
  423. t.Error("Expected len(row.Cells) == 4, got ", strconv.Itoa(len(row.Cells)))
  424. }
  425. cell1 = row.Cells[0]
  426. if cell1.String() != "A" {
  427. t.Error("Expected cell1.String() == 'A', got ", cell1.String())
  428. }
  429. cell2 = row.Cells[1]
  430. if cell2.String() != "B" {
  431. t.Error("Expected cell2.String() == 'B', got ", cell2.String())
  432. }
  433. cell3 = row.Cells[2]
  434. if cell3.String() != "C" {
  435. t.Error("Expected cell3.String() == 'C', got ", cell3.String())
  436. }
  437. cell4 = row.Cells[3]
  438. if cell4.String() != "D" {
  439. t.Error("Expected cell4.String() == 'D', got ", cell4.String())
  440. }
  441. row = rows[1]
  442. if len(row.Cells) != 4 {
  443. t.Error("Expected len(row.Cells) == 4, got ", strconv.Itoa(len(row.Cells)))
  444. }
  445. cell1 = row.Cells[0]
  446. if cell1.String() != "1" {
  447. t.Error("Expected cell1.String() == '1', got ", cell1.String())
  448. }
  449. cell2 = row.Cells[1]
  450. if cell2.String() != "" {
  451. t.Error("Expected cell2.String() == '', got ", cell2.String())
  452. }
  453. cell3 = row.Cells[2]
  454. if cell3.String() != "" {
  455. t.Error("Expected cell3.String() == '', got ", cell3.String())
  456. }
  457. cell4 = row.Cells[3]
  458. if cell4.String() != "" {
  459. t.Error("Expected cell4.String() == '', got ", cell4.String())
  460. }
  461. }