lib_test.go 28 KB

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