lib_test.go 29 KB

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