lib_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. package xlsx
  2. import (
  3. "bytes"
  4. "encoding/xml"
  5. "strconv"
  6. "strings"
  7. "testing"
  8. )
  9. // Test we can correctly open a XSLX file and return a xlsx.File
  10. // struct.
  11. func TestOpenFile(t *testing.T) {
  12. var xlsxFile *File
  13. var error error
  14. xlsxFile, error = OpenFile("testfile.xlsx")
  15. if error != nil {
  16. t.Error(error.Error())
  17. return
  18. }
  19. if xlsxFile == nil {
  20. t.Error("OpenFile returned nil FileInterface without generating an os.Error")
  21. return
  22. }
  23. }
  24. // Test that when we open a real XLSX file we create xlsx.Sheet
  25. // objects for the sheets inside the file and that these sheets are
  26. // themselves correct.
  27. func TestCreateSheet(t *testing.T) {
  28. var xlsxFile *File
  29. var error error
  30. var sheet *Sheet
  31. var row *Row
  32. xlsxFile, error = OpenFile("testfile.xlsx")
  33. if error != nil {
  34. t.Error(error.Error())
  35. return
  36. }
  37. if xlsxFile == nil {
  38. t.Error("OpenFile returned a nil File pointer but did not generate an error.")
  39. return
  40. }
  41. sheetLen := len(xlsxFile.Sheets)
  42. if sheetLen == 0 {
  43. t.Error("Expected len(xlsxFile.Sheets) > 0, but got ", sheetLen)
  44. return
  45. }
  46. sheet = xlsxFile.Sheets[0]
  47. rowLen := len(sheet.Rows)
  48. if rowLen != 2 {
  49. t.Error("Expected len(sheet.Rows) == 2, but got ", rowLen)
  50. return
  51. }
  52. row = sheet.Rows[0]
  53. if len(row.Cells) != 2 {
  54. t.Error("Expected len(row.Cells) == 2")
  55. return
  56. }
  57. cell := row.Cells[0]
  58. cellstring := cell.String()
  59. if cellstring != "Foo" {
  60. t.Error("Expected cell.String() == 'Foo', got ", cellstring)
  61. }
  62. }
  63. // Test that GetStyle correctly converts the xlsxStyle.Fonts.
  64. func TestGetStyleWithFonts(t *testing.T) {
  65. var cell *Cell
  66. var style *Style
  67. var xStyles *xlsxStyles
  68. var fonts []xlsxFont
  69. var cellXfs []xlsxXf
  70. fonts = make([]xlsxFont, 1)
  71. fonts[0] = xlsxFont{
  72. Sz: xlsxVal{Val: "10"},
  73. Name: xlsxVal{Val: "Calibra"}}
  74. cellXfs = make([]xlsxXf, 1)
  75. cellXfs[0] = xlsxXf{ApplyFont: true, FontId: 0}
  76. xStyles = &xlsxStyles{Fonts: fonts, CellXfs: cellXfs}
  77. cell = &Cell{Value: "123", styleIndex: 1, styles: xStyles}
  78. style = cell.GetStyle()
  79. if style == nil {
  80. t.Error("No style returned by cell.GetStyle()")
  81. }
  82. if style.Font.Size != 10 {
  83. t.Error("Expected style.Font.Size == 10, but got ", style.Font.Size)
  84. }
  85. if style.Font.Name != "Calibra" {
  86. t.Error("Expected style.Font.Name == 'Calibra', but got ", style.Font.Name)
  87. }
  88. }
  89. // Test that GetStyle correctly converts the xlsxStyle.Fills.
  90. func TestGetStyleWithFills(t *testing.T) {
  91. var cell *Cell
  92. var style *Style
  93. var xStyles *xlsxStyles
  94. var fills []xlsxFill
  95. var cellXfs []xlsxXf
  96. fills = make([]xlsxFill, 1)
  97. fills[0] = xlsxFill{
  98. PatternFill: xlsxPatternFill{
  99. PatternType: "solid",
  100. FgColor: xlsxColor{RGB: "FF000000"},
  101. BgColor: xlsxColor{RGB: "00FF0000"}}}
  102. cellXfs = make([]xlsxXf, 1)
  103. cellXfs[0] = xlsxXf{ApplyFill: true, FillId: 0}
  104. xStyles = &xlsxStyles{Fills: fills, CellXfs: cellXfs}
  105. cell = &Cell{Value: "123", styleIndex: 1, styles: xStyles}
  106. style = cell.GetStyle()
  107. fill := style.Fill
  108. if fill.PatternType != "solid" {
  109. t.Error("Expected fill.PatternType == 'solid', but got ",
  110. fill.PatternType)
  111. }
  112. if fill.BgColor != "00FF0000" {
  113. t.Error("Expected fill.BgColor == '00FF0000', but got ",
  114. fill.BgColor)
  115. }
  116. if fill.FgColor != "FF000000" {
  117. t.Error("Expected fill.FgColor == 'FF000000', but got ",
  118. fill.FgColor)
  119. }
  120. }
  121. // Test that GetStyle correctly converts the xlsxStyle.Borders.
  122. func TestGetStyleWithBorders(t *testing.T) {
  123. var cell *Cell
  124. var style *Style
  125. var xStyles *xlsxStyles
  126. var borders []xlsxBorder
  127. var cellXfs []xlsxXf
  128. borders = make([]xlsxBorder, 1)
  129. borders[0] = xlsxBorder{
  130. Left: xlsxLine{Style: "thin"},
  131. Right: xlsxLine{Style: "thin"},
  132. Top: xlsxLine{Style: "thin"},
  133. Bottom: xlsxLine{Style: "thin"}}
  134. cellXfs = make([]xlsxXf, 1)
  135. cellXfs[0] = xlsxXf{ApplyBorder: true, BorderId: 0}
  136. xStyles = &xlsxStyles{Borders: borders, CellXfs: cellXfs}
  137. cell = &Cell{Value: "123", styleIndex: 1, styles: xStyles}
  138. style = cell.GetStyle()
  139. border := style.Border
  140. if border.Left != "thin" {
  141. t.Error("Expected border.Left == 'thin', but got ",
  142. border.Left)
  143. }
  144. if border.Right != "thin" {
  145. t.Error("Expected border.Right == 'thin', but got ",
  146. border.Right)
  147. }
  148. if border.Top != "thin" {
  149. t.Error("Expected border.Top == 'thin', but got ",
  150. border.Top)
  151. }
  152. if border.Bottom != "thin" {
  153. t.Error("Expected border.Bottom == 'thin', but got ",
  154. border.Bottom)
  155. }
  156. }
  157. // Test that we can correctly extract a reference table from the
  158. // sharedStrings.xml file embedded in the XLSX file and return a
  159. // reference table of string values from it.
  160. func TestReadSharedStringsFromZipFile(t *testing.T) {
  161. var xlsxFile *File
  162. var error error
  163. xlsxFile, error = OpenFile("testfile.xlsx")
  164. if error != nil {
  165. t.Error(error.Error())
  166. return
  167. }
  168. if xlsxFile.referenceTable == nil {
  169. t.Error("expected non nil xlsxFile.referenceTable")
  170. return
  171. }
  172. }
  173. func testXf(t *testing.T, result, expected *xlsxXf) {
  174. if result.ApplyAlignment != expected.ApplyAlignment {
  175. t.Error("Expected result.ApplyAlignment == ", expected.ApplyAlignment,
  176. ", got", result.ApplyAlignment)
  177. return
  178. }
  179. if result.ApplyBorder != expected.ApplyBorder {
  180. t.Error("Expected result.ApplyBorder == ", expected.ApplyBorder,
  181. ", got ", result.ApplyBorder)
  182. return
  183. }
  184. if result.ApplyFont != expected.ApplyFont {
  185. t.Error("Expect result.ApplyFont == ", expected.ApplyFont,
  186. ", got ", result.ApplyFont)
  187. return
  188. }
  189. if result.ApplyFill != expected.ApplyFill {
  190. t.Error("Expected result.ApplyFill == ", expected.ApplyFill,
  191. ", got ", result.ApplyFill)
  192. return
  193. }
  194. if result.ApplyProtection != expected.ApplyProtection {
  195. t.Error("Expexcted result.ApplyProtection == ", expected.ApplyProtection,
  196. ", got ", result.ApplyProtection)
  197. return
  198. }
  199. if result.BorderId != expected.BorderId {
  200. t.Error("Expected BorderId == ", expected.BorderId,
  201. ". got ", result.BorderId)
  202. return
  203. }
  204. if result.FillId != expected.FillId {
  205. t.Error("Expected result.FillId == ", expected.FillId,
  206. ", got ", result.FillId)
  207. return
  208. }
  209. if result.FontId != expected.FontId {
  210. t.Error("Expected result.FontId == ", expected.FontId,
  211. ", got ", result.FontId)
  212. return
  213. }
  214. if result.NumFmtId != expected.NumFmtId {
  215. t.Error("Expected result.NumFmtId == ", expected.NumFmtId,
  216. ", got ", result.NumFmtId)
  217. return
  218. }
  219. }
  220. // We can correctly extract a style table from the style.xml file
  221. // embedded in the XLSX file and return a styles struct from it.
  222. func TestReadStylesFromZipFile(t *testing.T) {
  223. var xlsxFile *File
  224. var error error
  225. var fontCount, fillCount, borderCount, cellStyleXfCount, cellXfCount int
  226. var font xlsxFont
  227. var fill xlsxFill
  228. var border xlsxBorder
  229. var xf xlsxXf
  230. xlsxFile, error = OpenFile("testfile.xlsx")
  231. if error != nil {
  232. t.Error(error.Error())
  233. return
  234. }
  235. if xlsxFile.styles == nil {
  236. t.Error("expected non nil xlsxFile.styles")
  237. return
  238. }
  239. fontCount = len(xlsxFile.styles.Fonts)
  240. if fontCount != 4 {
  241. t.Error("expected exactly 4 xslxFonts, got ", fontCount)
  242. return
  243. }
  244. font = xlsxFile.styles.Fonts[0]
  245. if font.Sz.Val != "11" {
  246. t.Error("expected font.Sz.Val == 11, got ", font.Sz.Val)
  247. return
  248. }
  249. if font.Name.Val != "Calibri" {
  250. t.Error("expected font.Name.Val == 'Calibri', got ", font.Name.Val)
  251. return
  252. }
  253. fillCount = len(xlsxFile.styles.Fills)
  254. if fillCount != 3 {
  255. t.Error("Expected exactly 3 xlsxFills, got ", fillCount)
  256. return
  257. }
  258. fill = xlsxFile.styles.Fills[2]
  259. if fill.PatternFill.PatternType != "solid" {
  260. t.Error("Expected PatternFill.PatternType == 'solid', but got ",
  261. fill.PatternFill.PatternType)
  262. return
  263. }
  264. borderCount = len(xlsxFile.styles.Borders)
  265. if borderCount != 2 {
  266. t.Error("Expected exactly 2 xlsxBorders, got ", borderCount)
  267. return
  268. }
  269. border = xlsxFile.styles.Borders[1]
  270. if border.Left.Style != "thin" {
  271. t.Error("Expected border.Left.Style == 'thin', got ", border.Left.Style)
  272. return
  273. }
  274. if border.Right.Style != "thin" {
  275. t.Error("Expected border.Right.Style == 'thin', got ", border.Right.Style)
  276. return
  277. }
  278. if border.Top.Style != "thin" {
  279. t.Error("Expected border.Top.Style == 'thin', got ", border.Top.Style)
  280. return
  281. }
  282. if border.Bottom.Style != "thin" {
  283. t.Error("Expected border.Bottom.Style == 'thin', got ", border.Bottom.Style)
  284. return
  285. }
  286. cellStyleXfCount = len(xlsxFile.styles.CellStyleXfs)
  287. if cellStyleXfCount != 20 {
  288. t.Error("Expected excactly 20 cellStyleXfs, got ", cellStyleXfCount)
  289. return
  290. }
  291. xf = xlsxFile.styles.CellStyleXfs[0]
  292. expectedXf := &xlsxXf{
  293. ApplyAlignment: true,
  294. ApplyBorder: true,
  295. ApplyFont: true,
  296. ApplyFill: false,
  297. ApplyProtection: true,
  298. BorderId: 0,
  299. FillId: 0,
  300. FontId: 0,
  301. NumFmtId: 164}
  302. testXf(t, &xf, expectedXf)
  303. cellXfCount = len(xlsxFile.styles.CellXfs)
  304. if cellXfCount != 3 {
  305. t.Error("Expected excactly 3 cellXfs, got ", cellXfCount)
  306. return
  307. }
  308. xf = xlsxFile.styles.CellXfs[0]
  309. expectedXf = &xlsxXf{
  310. ApplyAlignment: false,
  311. ApplyBorder: false,
  312. ApplyFont: false,
  313. ApplyFill: false,
  314. ApplyProtection: false,
  315. BorderId: 0,
  316. FillId: 0,
  317. FontId: 0,
  318. NumFmtId: 164}
  319. testXf(t, &xf, expectedXf)
  320. }
  321. // We can correctly extract a map of relationship Ids to the worksheet files in
  322. // which they are contained from the XLSX file.
  323. func TestReadWorkbookRelationsFromZipFile(t *testing.T) {
  324. var xlsxFile *File
  325. var error error
  326. xlsxFile, error = OpenFile("testfile.xlsx")
  327. if error != nil {
  328. t.Error(error.Error())
  329. return
  330. }
  331. sheetCount := len(xlsxFile.Sheet)
  332. if sheetCount != 3 {
  333. t.Error("Expected 3 items in xlsxFile.Sheet, but found ", strconv.Itoa(sheetCount))
  334. }
  335. }
  336. // We can extract a map of relationship Ids to the worksheet files in
  337. // which they are contained from the XLSX file, even when the
  338. // worksheet files have arbitrary, non-numeric names.
  339. func TestReadWorkbookRelationsFromZipFileWithFunnyNames(t *testing.T) {
  340. var xlsxFile *File
  341. var error error
  342. xlsxFile, error = OpenFile("testrels.xlsx")
  343. if error != nil {
  344. t.Error(error.Error())
  345. return
  346. }
  347. sheetCount := len(xlsxFile.Sheet)
  348. if sheetCount != 2 {
  349. t.Error("Expected 3 items in xlsxFile.Sheet, but found ", strconv.Itoa(sheetCount))
  350. }
  351. bob := xlsxFile.Sheet["Bob"]
  352. row1 := bob.Rows[0]
  353. cell1 := row1.Cells[0]
  354. if cell1.String() != "I am Bob" {
  355. t.Error("Expected cell1.String() == 'I am Bob', but got '" + cell1.String() + "'")
  356. }
  357. }
  358. func TestLettersToNumeric(t *testing.T) {
  359. cases := map[string]int{"A": 0, "G": 6, "z": 25, "AA": 26, "Az": 51,
  360. "BA": 52, "Bz": 77, "ZA": 26*26 + 0, "ZZ": 26*26 + 25,
  361. "AAA": 26*26 + 26 + 0, "AMI": 1022}
  362. for input, ans := range cases {
  363. output := lettersToNumeric(input)
  364. if output != ans {
  365. t.Error("Expected output '"+input+"' == ", ans,
  366. "but got ", strconv.Itoa(output))
  367. }
  368. }
  369. }
  370. func TestLetterOnlyMapFunction(t *testing.T) {
  371. var input string = "ABC123"
  372. var output string = strings.Map(letterOnlyMapF, input)
  373. if output != "ABC" {
  374. t.Error("Expected output == 'ABC' but got ", output)
  375. }
  376. input = "abc123"
  377. output = strings.Map(letterOnlyMapF, input)
  378. if output != "ABC" {
  379. t.Error("Expected output == 'ABC' but got ", output)
  380. }
  381. }
  382. func TestIntOnlyMapFunction(t *testing.T) {
  383. var input string = "ABC123"
  384. var output string = strings.Map(intOnlyMapF, input)
  385. if output != "123" {
  386. t.Error("Expected output == '123' but got ", output)
  387. }
  388. }
  389. func TestGetCoordsFromCellIDString(t *testing.T) {
  390. var cellIDString string = "A3"
  391. var x, y int
  392. var error error
  393. x, y, error = getCoordsFromCellIDString(cellIDString)
  394. if error != nil {
  395. t.Error(error)
  396. }
  397. if x != 0 {
  398. t.Error("Expected x == 0, but got ", strconv.Itoa(x))
  399. }
  400. if y != 2 {
  401. t.Error("Expected y == 2, but got ", strconv.Itoa(y))
  402. }
  403. }
  404. func TestGetMaxMinFromDimensionRef(t *testing.T) {
  405. var dimensionRef string = "A1:B2"
  406. var minx, miny, maxx, maxy int
  407. var err error
  408. minx, miny, maxx, maxy, err = getMaxMinFromDimensionRef(dimensionRef)
  409. if err != nil {
  410. t.Error(err)
  411. }
  412. if minx != 0 {
  413. t.Error("Expected minx == 0, but got ", strconv.Itoa(minx))
  414. }
  415. if miny != 0 {
  416. t.Error("Expected miny == 0, but got ", strconv.Itoa(miny))
  417. }
  418. if maxx != 1 {
  419. t.Error("Expected maxx == 0, but got ", strconv.Itoa(maxx))
  420. }
  421. if maxy != 1 {
  422. t.Error("Expected maxy == 0, but got ", strconv.Itoa(maxy))
  423. }
  424. }
  425. func TestGetRangeFromString(t *testing.T) {
  426. var rangeString string
  427. var lower, upper int
  428. var error error
  429. rangeString = "1:3"
  430. lower, upper, error = getRangeFromString(rangeString)
  431. if error != nil {
  432. t.Error(error)
  433. }
  434. if lower != 1 {
  435. t.Error("Expected lower bound == 1, but got ", strconv.Itoa(lower))
  436. }
  437. if upper != 3 {
  438. t.Error("Expected upper bound == 3, but got ", strconv.Itoa(upper))
  439. }
  440. }
  441. func TestMakeRowFromSpan(t *testing.T) {
  442. var rangeString string
  443. var row *Row
  444. var length int
  445. rangeString = "1:3"
  446. row = makeRowFromSpan(rangeString)
  447. length = len(row.Cells)
  448. if length != 3 {
  449. t.Error("Expected a row with 3 cells, but got ", strconv.Itoa(length))
  450. }
  451. rangeString = "5:7" // Note - we ignore lower bound!
  452. row = makeRowFromSpan(rangeString)
  453. length = len(row.Cells)
  454. if length != 7 {
  455. t.Error("Expected a row with 7 cells, but got ", strconv.Itoa(length))
  456. }
  457. rangeString = "1:1"
  458. row = makeRowFromSpan(rangeString)
  459. length = len(row.Cells)
  460. if length != 1 {
  461. t.Error("Expected a row with 1 cells, but got ", strconv.Itoa(length))
  462. }
  463. }
  464. func TestReadRowsFromSheet(t *testing.T) {
  465. var sharedstringsXML = bytes.NewBufferString(`
  466. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  467. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="4" uniqueCount="4">
  468. <si>
  469. <t>Foo</t>
  470. </si>
  471. <si>
  472. <t>Bar</t>
  473. </si>
  474. <si>
  475. <t xml:space="preserve">Baz </t>
  476. </si>
  477. <si>
  478. <t>Quuk</t>
  479. </si>
  480. </sst>`)
  481. var sheetxml = bytes.NewBufferString(`
  482. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  483. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  484. xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  485. <dimension ref="A1:B2"/>
  486. <sheetViews>
  487. <sheetView tabSelected="1" workbookViewId="0">
  488. <selection activeCell="C2" sqref="C2"/>
  489. </sheetView>
  490. </sheetViews>
  491. <sheetFormatPr baseColWidth="10" defaultRowHeight="15"/>
  492. <sheetData>
  493. <row r="1" spans="1:2">
  494. <c r="A1" t="s">
  495. <v>0</v>
  496. </c>
  497. <c r="B1" t="s">
  498. <v>1</v>
  499. </c>
  500. </row>
  501. <row r="2" spans="1:2">
  502. <c r="A2" t="s">
  503. <v>2</v>
  504. </c>
  505. <c r="B2" t="s">
  506. <v>3</v>
  507. </c>
  508. </row>
  509. </sheetData>
  510. <pageMargins left="0.7" right="0.7"
  511. top="0.78740157499999996"
  512. bottom="0.78740157499999996"
  513. header="0.3"
  514. footer="0.3"/>
  515. </worksheet>`)
  516. worksheet := new(xlsxWorksheet)
  517. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  518. if error != nil {
  519. t.Error(error.Error())
  520. return
  521. }
  522. sst := new(xlsxSST)
  523. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  524. if error != nil {
  525. t.Error(error.Error())
  526. return
  527. }
  528. file := new(File)
  529. file.referenceTable = MakeSharedStringRefTable(sst)
  530. rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
  531. if maxRows != 2 {
  532. t.Error("Expected maxRows == 2")
  533. }
  534. if maxCols != 2 {
  535. t.Error("Expected maxCols == 2")
  536. }
  537. row := rows[0]
  538. if len(row.Cells) != 2 {
  539. t.Error("Expected len(row.Cells) == 2, got ", strconv.Itoa(len(row.Cells)))
  540. }
  541. cell1 := row.Cells[0]
  542. if cell1.String() != "Foo" {
  543. t.Error("Expected cell1.String() == 'Foo', got ", cell1.String())
  544. }
  545. cell2 := row.Cells[1]
  546. if cell2.String() != "Bar" {
  547. t.Error("Expected cell2.String() == 'Bar', got ", cell2.String())
  548. }
  549. }
  550. func TestReadRowsFromSheetWithLeadingEmptyRows(t *testing.T) {
  551. var sharedstringsXML = bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  552. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="2" uniqueCount="2"><si><t>ABC</t></si><si><t>DEF</t></si></sst>`)
  553. var sheetxml = bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  554. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">
  555. <dimension ref="A4:A5"/>
  556. <sheetViews>
  557. <sheetView tabSelected="1" workbookViewId="0">
  558. <selection activeCell="A2" sqref="A2"/>
  559. </sheetView>
  560. </sheetViews>
  561. <sheetFormatPr baseColWidth="10" defaultRowHeight="15" x14ac:dyDescent="0"/>
  562. <sheetData>
  563. <row r="4" spans="1:1">
  564. <c r="A4" t="s">
  565. <v>0</v>
  566. </c>
  567. </row>
  568. <row r="5" spans="1:1">
  569. <c r="A5" t="s">
  570. <v>1</v>
  571. </c>
  572. </row>
  573. </sheetData>
  574. <pageMargins left="0.75" right="0.75" top="1" bottom="1" header="0.5" footer="0.5"/>
  575. <pageSetup paperSize="9" orientation="portrait" horizontalDpi="4294967292" verticalDpi="4294967292"/>
  576. <extLst>
  577. <ext uri="{64002731-A6B0-56B0-2670-7721B7C09600}" xmlns:mx="http://schemas.microsoft.com/office/mac/excel/2008/main">
  578. <mx:PLV Mode="0" OnePage="0" WScale="0"/>
  579. </ext>
  580. </extLst>
  581. </worksheet>
  582. `)
  583. worksheet := new(xlsxWorksheet)
  584. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  585. if error != nil {
  586. t.Error(error.Error())
  587. return
  588. }
  589. sst := new(xlsxSST)
  590. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  591. if error != nil {
  592. t.Error(error.Error())
  593. return
  594. }
  595. file := new(File)
  596. file.referenceTable = MakeSharedStringRefTable(sst)
  597. rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
  598. if maxRows != 2 {
  599. t.Error("Expected maxRows == 2, got ", strconv.Itoa(len(rows)))
  600. }
  601. if maxCols != 1 {
  602. t.Error("Expected maxCols == 1, got ", strconv.Itoa(maxCols))
  603. }
  604. }
  605. func TestReadRowsFromSheetWithEmptyCells(t *testing.T) {
  606. var sharedstringsXML = bytes.NewBufferString(`
  607. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  608. <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>`)
  609. var sheetxml = bytes.NewBufferString(`
  610. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  611. <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"/>
  612. <sheetData>
  613. <row r="1" spans="1:3">
  614. <c r="A1" t="s">
  615. <v>
  616. 0
  617. </v>
  618. </c>
  619. <c r="B1" t="s">
  620. <v>
  621. 1
  622. </v>
  623. </c>
  624. <c r="C1" t="s">
  625. <v>
  626. 2
  627. </v>
  628. </c>
  629. </row>
  630. <row r="2" spans="1:3">
  631. <c r="A2" t="s">
  632. <v>
  633. 3
  634. </v>
  635. </c>
  636. <c r="B2" t="s">
  637. <v>
  638. 4
  639. </v>
  640. </c>
  641. <c r="C2" t="s">
  642. <v>
  643. 3
  644. </v>
  645. </c>
  646. </row>
  647. <row r="3" spans="1:3">
  648. <c r="A3" t="s">
  649. <v>
  650. 4
  651. </v>
  652. </c>
  653. <c r="C3" t="s">
  654. <v>
  655. 3
  656. </v>
  657. </c>
  658. </row>
  659. </sheetData>
  660. <pageMargins left="0.7" right="0.7" top="0.78740157499999996" bottom="0.78740157499999996" header="0.3" footer="0.3"/>
  661. </worksheet>
  662. `)
  663. worksheet := new(xlsxWorksheet)
  664. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  665. if error != nil {
  666. t.Error(error.Error())
  667. return
  668. }
  669. sst := new(xlsxSST)
  670. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  671. if error != nil {
  672. t.Error(error.Error())
  673. return
  674. }
  675. file := new(File)
  676. file.referenceTable = MakeSharedStringRefTable(sst)
  677. rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
  678. if maxRows != 3 {
  679. t.Error("Expected maxRows == 3, got ", strconv.Itoa(len(rows)))
  680. }
  681. if maxCols != 3 {
  682. t.Error("Expected maxCols == 3, got ", strconv.Itoa(maxCols))
  683. }
  684. row := rows[2]
  685. if len(row.Cells) != 3 {
  686. t.Error("Expected len(row.Cells) == 3, got ", strconv.Itoa(len(row.Cells)))
  687. }
  688. cell1 := row.Cells[0]
  689. if cell1.String() != "No" {
  690. t.Error("Expected cell1.String() == 'No', got ", cell1.String())
  691. }
  692. cell2 := row.Cells[1]
  693. if cell2.String() != "" {
  694. t.Error("Expected cell2.String() == '', got ", cell2.String())
  695. }
  696. cell3 := row.Cells[2]
  697. if cell3.String() != "Yes" {
  698. t.Error("Expected cell3.String() == 'Yes', got ", cell3.String())
  699. }
  700. }
  701. func TestReadRowsFromSheetWithTrailingEmptyCells(t *testing.T) {
  702. var row *Row
  703. var cell1, cell2, cell3, cell4 *Cell
  704. var sharedstringsXML = bytes.NewBufferString(`
  705. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  706. <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>`)
  707. var sheetxml = bytes.NewBufferString(`
  708. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  709. <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>
  710. `)
  711. worksheet := new(xlsxWorksheet)
  712. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  713. if error != nil {
  714. t.Error(error.Error())
  715. return
  716. }
  717. sst := new(xlsxSST)
  718. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  719. if error != nil {
  720. t.Error(error.Error())
  721. return
  722. }
  723. file := new(File)
  724. file.referenceTable = MakeSharedStringRefTable(sst)
  725. rows, maxCol, maxRow := readRowsFromSheet(worksheet, file)
  726. if maxCol != 4 {
  727. t.Error("Expected maxCol == 4, got ", strconv.Itoa(maxCol))
  728. }
  729. if maxRow != 8 {
  730. t.Error("Expected maxRow == 8, got ", strconv.Itoa(maxRow))
  731. }
  732. row = rows[0]
  733. if len(row.Cells) != 4 {
  734. t.Error("Expected len(row.Cells) == 4, got ", strconv.Itoa(len(row.Cells)))
  735. }
  736. cell1 = row.Cells[0]
  737. if cell1.String() != "A" {
  738. t.Error("Expected cell1.String() == 'A', got ", cell1.String())
  739. }
  740. cell2 = row.Cells[1]
  741. if cell2.String() != "B" {
  742. t.Error("Expected cell2.String() == 'B', got ", cell2.String())
  743. }
  744. cell3 = row.Cells[2]
  745. if cell3.String() != "C" {
  746. t.Error("Expected cell3.String() == 'C', got ", cell3.String())
  747. }
  748. cell4 = row.Cells[3]
  749. if cell4.String() != "D" {
  750. t.Error("Expected cell4.String() == 'D', got ", cell4.String())
  751. }
  752. row = rows[1]
  753. if len(row.Cells) != 4 {
  754. t.Error("Expected len(row.Cells) == 4, got ", strconv.Itoa(len(row.Cells)))
  755. }
  756. cell1 = row.Cells[0]
  757. if cell1.String() != "1" {
  758. t.Error("Expected cell1.String() == '1', got ", cell1.String())
  759. }
  760. cell2 = row.Cells[1]
  761. if cell2.String() != "" {
  762. t.Error("Expected cell2.String() == '', got ", cell2.String())
  763. }
  764. cell3 = row.Cells[2]
  765. if cell3.String() != "" {
  766. t.Error("Expected cell3.String() == '', got ", cell3.String())
  767. }
  768. cell4 = row.Cells[3]
  769. if cell4.String() != "" {
  770. t.Error("Expected cell4.String() == '', got ", cell4.String())
  771. }
  772. }