file_test.go 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. package xlsx
  2. import (
  3. "encoding/xml"
  4. "path/filepath"
  5. "time"
  6. . "gopkg.in/check.v1"
  7. )
  8. type FileSuite struct{}
  9. var _ = Suite(&FileSuite{})
  10. // Test we can correctly open a XSLX file and return a xlsx.File
  11. // struct.
  12. func (l *FileSuite) TestOpenFile(c *C) {
  13. var xlsxFile *File
  14. var error error
  15. xlsxFile, error = OpenFile("./testdocs/testfile.xlsx")
  16. c.Assert(error, IsNil)
  17. c.Assert(xlsxFile, NotNil)
  18. }
  19. func (l *FileSuite) TestPartialReadsWithFewSharedStrings(c *C) {
  20. rowLimit := 10
  21. start := time.Now()
  22. file, err := OpenFileWithRowLimit("testdocs/large_sheet_no_shared_strings_no_dimension_tag.xlsx", rowLimit)
  23. if err != nil {
  24. c.Fatal(err)
  25. }
  26. timeSpent := time.Since(start)
  27. timeLimit := 100 * time.Millisecond
  28. if timeSpent > timeLimit {
  29. c.Errorf("Reading %v rows from a sheet with ~31,000 rows and few shared strings took %v, must take less than %v", rowLimit, timeSpent, timeLimit)
  30. }
  31. if len(file.Sheets[0].Rows) != rowLimit {
  32. c.Errorf("Expected sheet to have %v rows, but found %v rows", rowLimit, len(file.Sheets[0].Rows))
  33. }
  34. }
  35. func (l *FileSuite) TestPartialReadsWithSharedStrings(c *C) {
  36. rowLimit := 10
  37. start := time.Now()
  38. file, err := OpenFileWithRowLimit("testdocs/large_sheet_large_sharedstrings_dimension_tag.xlsx", rowLimit)
  39. if err != nil {
  40. c.Fatal(err)
  41. }
  42. timeSpent := time.Since(start)
  43. timeLimit := time.Second
  44. if timeSpent > timeLimit {
  45. c.Errorf("Reading %v rows from a sheet with ~31,000 rows and a large shared strings took %v, must take less than %v", rowLimit, timeSpent, timeLimit)
  46. }
  47. // This is testing that the sheet was truncated, but it is also testing that the dimension tag was ignored.
  48. // If the dimension tag is not correctly ignored, there will be 10 rows of the data, plus ~31k empty rows tacked on.
  49. if len(file.Sheets[0].Rows) != rowLimit {
  50. c.Errorf("Expected sheet to have %v rows, but found %v rows", rowLimit, len(file.Sheets[0].Rows))
  51. }
  52. }
  53. func (l *FileSuite) TestPartialReadsWithFewerRowsThanRequested(c *C) {
  54. rowLimit := 10
  55. file, err := OpenFileWithRowLimit("testdocs/testfile.xlsx", rowLimit)
  56. if err != nil {
  57. c.Fatal(err)
  58. }
  59. if len(file.Sheets[0].Rows) != 2 {
  60. c.Errorf("Expected sheet to have %v rows, but found %v rows", 2, len(file.Sheets[0].Rows))
  61. }
  62. }
  63. func (l *FileSuite) TestOpenFileWithoutStyleAndSharedStrings(c *C) {
  64. var xlsxFile *File
  65. var error error
  66. xlsxFile, error = OpenFile("./testdocs/noStylesAndSharedStringsTest.xlsx")
  67. c.Assert(error, IsNil)
  68. c.Assert(xlsxFile, NotNil)
  69. }
  70. func (l *FileSuite) TestOpenFileWithChartsheet(c *C) {
  71. xlsxFile, error := OpenFile("./testdocs/testchartsheet.xlsx")
  72. c.Assert(error, IsNil)
  73. c.Assert(xlsxFile, NotNil)
  74. }
  75. // Test that we can correctly extract a reference table from the
  76. // sharedStrings.xml file embedded in the XLSX file and return a
  77. // reference table of string values from it.
  78. func (l *FileSuite) TestReadSharedStringsFromZipFile(c *C) {
  79. var xlsxFile *File
  80. var err error
  81. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  82. c.Assert(err, IsNil)
  83. c.Assert(xlsxFile.referenceTable, NotNil)
  84. }
  85. // Helper function used to test contents of a given xlsxXf against
  86. // expectations.
  87. func testXf(c *C, result, expected *xlsxXf) {
  88. c.Assert(result.ApplyAlignment, Equals, expected.ApplyAlignment)
  89. c.Assert(result.ApplyBorder, Equals, expected.ApplyBorder)
  90. c.Assert(result.ApplyFont, Equals, expected.ApplyFont)
  91. c.Assert(result.ApplyFill, Equals, expected.ApplyFill)
  92. c.Assert(result.ApplyProtection, Equals, expected.ApplyProtection)
  93. c.Assert(result.BorderId, Equals, expected.BorderId)
  94. c.Assert(result.FillId, Equals, expected.FillId)
  95. c.Assert(result.FontId, Equals, expected.FontId)
  96. c.Assert(result.NumFmtId, Equals, expected.NumFmtId)
  97. }
  98. // We can correctly extract a style table from the style.xml file
  99. // embedded in the XLSX file and return a styles struct from it.
  100. func (l *FileSuite) TestReadStylesFromZipFile(c *C) {
  101. var xlsxFile *File
  102. var err error
  103. var fontCount, fillCount, borderCount, cellStyleXfCount, cellXfCount int
  104. var font xlsxFont
  105. var fill xlsxFill
  106. var border xlsxBorder
  107. var xf xlsxXf
  108. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  109. c.Assert(err, IsNil)
  110. c.Assert(xlsxFile.styles, NotNil)
  111. fontCount = len(xlsxFile.styles.Fonts.Font)
  112. c.Assert(fontCount, Equals, 4)
  113. font = xlsxFile.styles.Fonts.Font[0]
  114. c.Assert(font.Sz.Val, Equals, "11")
  115. c.Assert(font.Name.Val, Equals, "Calibri")
  116. fillCount = xlsxFile.styles.Fills.Count
  117. c.Assert(fillCount, Equals, 3)
  118. fill = xlsxFile.styles.Fills.Fill[2]
  119. c.Assert(fill.PatternFill.PatternType, Equals, "solid")
  120. borderCount = xlsxFile.styles.Borders.Count
  121. c.Assert(borderCount, Equals, 2)
  122. border = xlsxFile.styles.Borders.Border[1]
  123. c.Assert(border.Left.Style, Equals, "thin")
  124. c.Assert(border.Right.Style, Equals, "thin")
  125. c.Assert(border.Top.Style, Equals, "thin")
  126. c.Assert(border.Bottom.Style, Equals, "thin")
  127. cellStyleXfCount = xlsxFile.styles.CellStyleXfs.Count
  128. c.Assert(cellStyleXfCount, Equals, 20)
  129. xf = xlsxFile.styles.CellStyleXfs.Xf[0]
  130. expectedXf := &xlsxXf{
  131. ApplyAlignment: true,
  132. ApplyBorder: true,
  133. ApplyFont: true,
  134. ApplyFill: false,
  135. ApplyProtection: true,
  136. BorderId: 0,
  137. FillId: 0,
  138. FontId: 0,
  139. NumFmtId: 164}
  140. testXf(c, &xf, expectedXf)
  141. c.Assert(xf.Alignment, NotNil)
  142. c.Assert(xf.Alignment.Horizontal, Equals, "general")
  143. c.Assert(xf.Alignment.Indent, Equals, 0)
  144. c.Assert(xf.Alignment.ShrinkToFit, Equals, false)
  145. c.Assert(xf.Alignment.TextRotation, Equals, 0)
  146. c.Assert(xf.Alignment.Vertical, Equals, "bottom")
  147. c.Assert(xf.Alignment.WrapText, Equals, false)
  148. cellXfCount = xlsxFile.styles.CellXfs.Count
  149. c.Assert(cellXfCount, Equals, 3)
  150. xf = xlsxFile.styles.CellXfs.Xf[0]
  151. expectedXf = &xlsxXf{
  152. ApplyAlignment: false,
  153. ApplyBorder: false,
  154. ApplyFont: false,
  155. ApplyFill: false,
  156. ApplyProtection: false,
  157. BorderId: 0,
  158. FillId: 0,
  159. FontId: 0,
  160. NumFmtId: 164}
  161. testXf(c, &xf, expectedXf)
  162. }
  163. // We can correctly extract a map of relationship Ids to the worksheet files in
  164. // which they are contained from the XLSX file.
  165. func (l *FileSuite) TestReadWorkbookRelationsFromZipFile(c *C) {
  166. var xlsxFile *File
  167. var err error
  168. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  169. c.Assert(err, IsNil)
  170. c.Assert(len(xlsxFile.Sheets), Equals, 3)
  171. sheet, ok := xlsxFile.Sheet["Tabelle1"]
  172. c.Assert(ok, Equals, true)
  173. c.Assert(sheet, NotNil)
  174. }
  175. // Style information is correctly extracted from the zipped XLSX file.
  176. func (l *FileSuite) TestGetStyleFromZipFile(c *C) {
  177. var xlsxFile *File
  178. var err error
  179. var style *Style
  180. var val string
  181. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  182. c.Assert(err, IsNil)
  183. sheetCount := len(xlsxFile.Sheets)
  184. c.Assert(sheetCount, Equals, 3)
  185. tabelle1 := xlsxFile.Sheet["Tabelle1"]
  186. row0 := tabelle1.Rows[0]
  187. cellFoo := row0.Cells[0]
  188. style = cellFoo.GetStyle()
  189. if val, err = cellFoo.FormattedValue(); err != nil {
  190. c.Error(err)
  191. }
  192. c.Assert(val, Equals, "Foo")
  193. c.Assert(style.Fill.BgColor, Equals, "FF33CCCC")
  194. c.Assert(style.ApplyFill, Equals, false)
  195. c.Assert(style.ApplyFont, Equals, true)
  196. row1 := tabelle1.Rows[1]
  197. cellQuuk := row1.Cells[1]
  198. style = cellQuuk.GetStyle()
  199. if val, err = cellQuuk.FormattedValue(); err != nil {
  200. c.Error(err)
  201. }
  202. c.Assert(val, Equals, "Quuk")
  203. c.Assert(style.Border.Left, Equals, "thin")
  204. c.Assert(style.ApplyBorder, Equals, true)
  205. cellBar := row0.Cells[1]
  206. if val, err = cellBar.FormattedValue(); err != nil {
  207. c.Error(err)
  208. }
  209. c.Assert(val, Equals, "Bar")
  210. c.Assert(cellBar.GetStyle().Fill.BgColor, Equals, "")
  211. }
  212. // Test we can create a File object from scratch
  213. func (l *FileSuite) TestCreateFile(c *C) {
  214. var xlsxFile *File
  215. xlsxFile = NewFile()
  216. c.Assert(xlsxFile, NotNil)
  217. }
  218. // Test that when we open a real XLSX file we create xlsx.Sheet
  219. // objects for the sheets inside the file and that these sheets are
  220. // themselves correct.
  221. func (l *FileSuite) TestCreateSheet(c *C) {
  222. var xlsxFile *File
  223. var err error
  224. var sheet *Sheet
  225. var row *Row
  226. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  227. c.Assert(err, IsNil)
  228. c.Assert(xlsxFile, NotNil)
  229. sheetLen := len(xlsxFile.Sheets)
  230. c.Assert(sheetLen, Equals, 3)
  231. sheet = xlsxFile.Sheet["Tabelle1"]
  232. rowLen := len(sheet.Rows)
  233. c.Assert(rowLen, Equals, 2)
  234. row = sheet.Rows[0]
  235. c.Assert(len(row.Cells), Equals, 2)
  236. cell := row.Cells[0]
  237. if val, err := cell.FormattedValue(); err != nil {
  238. c.Error(err)
  239. } else {
  240. c.Assert(val, Equals, "Foo")
  241. }
  242. }
  243. // Test that we can add a sheet to a File
  244. func (l *FileSuite) TestAddSheet(c *C) {
  245. var f *File
  246. f = NewFile()
  247. sheet, err := f.AddSheet("MySheet")
  248. c.Assert(err, IsNil)
  249. c.Assert(sheet, NotNil)
  250. c.Assert(len(f.Sheets), Equals, 1)
  251. c.Assert(f.Sheet["MySheet"], Equals, sheet)
  252. }
  253. // Test that AddSheet returns an error if you try to add two sheets with the same name
  254. func (l *FileSuite) TestAddSheetWithDuplicateName(c *C) {
  255. f := NewFile()
  256. _, err := f.AddSheet("MySheet")
  257. c.Assert(err, IsNil)
  258. _, err = f.AddSheet("MySheet")
  259. c.Assert(err, ErrorMatches, "duplicate sheet name 'MySheet'.")
  260. }
  261. // Test that we can append a sheet to a File
  262. func (l *FileSuite) TestAppendSheet(c *C) {
  263. var f *File
  264. f = NewFile()
  265. s := Sheet{}
  266. sheet, err := f.AppendSheet(s, "MySheet")
  267. c.Assert(err, IsNil)
  268. c.Assert(sheet, NotNil)
  269. c.Assert(len(f.Sheets), Equals, 1)
  270. c.Assert(f.Sheet["MySheet"], Equals, sheet)
  271. }
  272. // Test that AppendSheet returns an error if you try to add two sheets with the same name
  273. func (l *FileSuite) TestAppendSheetWithDuplicateName(c *C) {
  274. f := NewFile()
  275. s := Sheet{}
  276. _, err := f.AppendSheet(s, "MySheet")
  277. c.Assert(err, IsNil)
  278. _, err = f.AppendSheet(s, "MySheet")
  279. c.Assert(err, ErrorMatches, "duplicate sheet name 'MySheet'.")
  280. }
  281. // Test that we can get the Nth sheet
  282. func (l *FileSuite) TestNthSheet(c *C) {
  283. var f *File
  284. f = NewFile()
  285. sheet, _ := f.AddSheet("MySheet")
  286. sheetByIndex := f.Sheets[0]
  287. sheetByName := f.Sheet["MySheet"]
  288. c.Assert(sheetByIndex, NotNil)
  289. c.Assert(sheetByIndex, Equals, sheet)
  290. c.Assert(sheetByIndex, Equals, sheetByName)
  291. }
  292. // Test that we can create a Workbook and marshal it to XML.
  293. func (l *FileSuite) TestMarshalWorkbook(c *C) {
  294. var f *File
  295. f = NewFile()
  296. f.AddSheet("MyFirstSheet")
  297. f.AddSheet("MySecondSheet")
  298. workbook := f.makeWorkbook()
  299. workbook.Sheets.Sheet[0] = xlsxSheet{
  300. Name: "MyFirstSheet",
  301. SheetId: "1",
  302. Id: "rId1",
  303. State: "visible"}
  304. workbook.Sheets.Sheet[1] = xlsxSheet{
  305. Name: "MySecondSheet",
  306. SheetId: "2",
  307. Id: "rId2",
  308. State: "visible"}
  309. expectedWorkbook := `<?xml version="1.0" encoding="UTF-8"?>
  310. <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><fileVersion appName="Go XLSX"></fileVersion><workbookPr showObjects="all" date1904="false"></workbookPr><workbookProtection></workbookProtection><bookViews><workbookView showHorizontalScroll="true" showVerticalScroll="true" showSheetTabs="true" tabRatio="204" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"></workbookView></bookViews><sheets><sheet name="MyFirstSheet" sheetId="1" r:id="rId1" state="visible"></sheet><sheet name="MySecondSheet" sheetId="2" r:id="rId2" state="visible"></sheet></sheets><definedNames></definedNames><calcPr iterateCount="100" refMode="A1" iterateDelta="0.001"></calcPr></workbook>`
  311. output, err := xml.Marshal(workbook)
  312. c.Assert(err, IsNil)
  313. outputStr := replaceRelationshipsNameSpace(string(output))
  314. stringOutput := xml.Header + outputStr
  315. c.Assert(stringOutput, Equals, expectedWorkbook)
  316. }
  317. // Test that we can marshall a File to a collection of xml files
  318. func (l *FileSuite) TestMarshalFile(c *C) {
  319. var f *File
  320. f = NewFile()
  321. sheet1, _ := f.AddSheet("MySheet")
  322. row1 := sheet1.AddRow()
  323. cell1 := row1.AddCell()
  324. cell1.SetString("A cell!")
  325. sheet2, _ := f.AddSheet("AnotherSheet")
  326. row2 := sheet2.AddRow()
  327. cell2 := row2.AddCell()
  328. cell2.SetString("A cell!")
  329. parts, err := f.MarshallParts()
  330. c.Assert(err, IsNil)
  331. c.Assert(len(parts), Equals, 11)
  332. // sheets
  333. expectedSheet1 := `<?xml version="1.0" encoding="UTF-8"?>
  334. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetPr filterMode="false"><pageSetUpPr fitToPage="false"></pageSetUpPr></sheetPr><dimension ref="A1"></dimension><sheetViews><sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"><selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"></selection></sheetView></sheetViews><sheetFormatPr defaultRowHeight="12.85"></sheetFormatPr><cols><col collapsed="false" hidden="false" max="1" min="1" style="1" width="9.5"></col></cols><sheetData><row r="1"><c r="A1" s="1" t="s"><v>0</v></c></row></sheetData><printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"></printOptions><pageMargins left="0.7875" right="0.7875" top="1.05277777777778" bottom="1.05277777777778" header="0.7875" footer="0.7875"></pageMargins><pageSetup paperSize="9" scale="100" firstPageNumber="1" fitToWidth="1" fitToHeight="1" pageOrder="downThenOver" orientation="portrait" usePrinterDefaults="false" blackAndWhite="false" draft="false" cellComments="none" useFirstPageNumber="true" horizontalDpi="300" verticalDpi="300" copies="1"></pageSetup><headerFooter differentFirst="false" differentOddEven="false"><oddHeader>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12&amp;A</oddHeader><oddFooter>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12Page &amp;P</oddFooter></headerFooter></worksheet>`
  335. c.Assert(parts["xl/worksheets/sheet1.xml"], Equals, expectedSheet1)
  336. expectedSheet2 := `<?xml version="1.0" encoding="UTF-8"?>
  337. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetPr filterMode="false"><pageSetUpPr fitToPage="false"></pageSetUpPr></sheetPr><dimension ref="A1"></dimension><sheetViews><sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="false" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"><selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"></selection></sheetView></sheetViews><sheetFormatPr defaultRowHeight="12.85"></sheetFormatPr><cols><col collapsed="false" hidden="false" max="1" min="1" style="1" width="9.5"></col></cols><sheetData><row r="1"><c r="A1" s="1" t="s"><v>0</v></c></row></sheetData><printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"></printOptions><pageMargins left="0.7875" right="0.7875" top="1.05277777777778" bottom="1.05277777777778" header="0.7875" footer="0.7875"></pageMargins><pageSetup paperSize="9" scale="100" firstPageNumber="1" fitToWidth="1" fitToHeight="1" pageOrder="downThenOver" orientation="portrait" usePrinterDefaults="false" blackAndWhite="false" draft="false" cellComments="none" useFirstPageNumber="true" horizontalDpi="300" verticalDpi="300" copies="1"></pageSetup><headerFooter differentFirst="false" differentOddEven="false"><oddHeader>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12&amp;A</oddHeader><oddFooter>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12Page &amp;P</oddFooter></headerFooter></worksheet>`
  338. c.Assert(parts["xl/worksheets/sheet2.xml"], Equals, expectedSheet2)
  339. // .rels.xml
  340. expectedRels := `<?xml version="1.0" encoding="UTF-8"?>
  341. <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  342. <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
  343. <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
  344. <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
  345. </Relationships>`
  346. c.Assert(parts["_rels/.rels"], Equals, expectedRels)
  347. // app.xml
  348. expectedApp := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  349. <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  350. <TotalTime>0</TotalTime>
  351. <Application>Go XLSX</Application>
  352. </Properties>`
  353. c.Assert(parts["docProps/app.xml"], Equals, expectedApp)
  354. // core.xml
  355. expectedCore := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  356. <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></cp:coreProperties>`
  357. c.Assert(parts["docProps/core.xml"], Equals, expectedCore)
  358. // theme1.xml
  359. expectedTheme := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  360. <a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office-Design">
  361. <a:themeElements>
  362. <a:clrScheme name="Office">
  363. <a:dk1>
  364. <a:sysClr val="windowText" lastClr="000000"/>
  365. </a:dk1>
  366. <a:lt1>
  367. <a:sysClr val="window" lastClr="FFFFFF"/>
  368. </a:lt1>
  369. <a:dk2>
  370. <a:srgbClr val="1F497D"/>
  371. </a:dk2>
  372. <a:lt2>
  373. <a:srgbClr val="EEECE1"/>
  374. </a:lt2>
  375. <a:accent1>
  376. <a:srgbClr val="4F81BD"/>
  377. </a:accent1>
  378. <a:accent2>
  379. <a:srgbClr val="C0504D"/>
  380. </a:accent2>
  381. <a:accent3>
  382. <a:srgbClr val="9BBB59"/>
  383. </a:accent3>
  384. <a:accent4>
  385. <a:srgbClr val="8064A2"/>
  386. </a:accent4>
  387. <a:accent5>
  388. <a:srgbClr val="4BACC6"/>
  389. </a:accent5>
  390. <a:accent6>
  391. <a:srgbClr val="F79646"/>
  392. </a:accent6>
  393. <a:hlink>
  394. <a:srgbClr val="0000FF"/>
  395. </a:hlink>
  396. <a:folHlink>
  397. <a:srgbClr val="800080"/>
  398. </a:folHlink>
  399. </a:clrScheme>
  400. <a:fontScheme name="Office">
  401. <a:majorFont>
  402. <a:latin typeface="Cambria"/>
  403. <a:ea typeface=""/>
  404. <a:cs typeface=""/>
  405. <a:font script="Jpan" typeface="MS Pゴシック"/>
  406. <a:font script="Hang" typeface="맑은 고딕"/>
  407. <a:font script="Hans" typeface="宋体"/>
  408. <a:font script="Hant" typeface="新細明體"/>
  409. <a:font script="Arab" typeface="Times New Roman"/>
  410. <a:font script="Hebr" typeface="Times New Roman"/>
  411. <a:font script="Thai" typeface="Tahoma"/>
  412. <a:font script="Ethi" typeface="Nyala"/>
  413. <a:font script="Beng" typeface="Vrinda"/>
  414. <a:font script="Gujr" typeface="Shruti"/>
  415. <a:font script="Khmr" typeface="MoolBoran"/>
  416. <a:font script="Knda" typeface="Tunga"/>
  417. <a:font script="Guru" typeface="Raavi"/>
  418. <a:font script="Cans" typeface="Euphemia"/>
  419. <a:font script="Cher" typeface="Plantagenet Cherokee"/>
  420. <a:font script="Yiii" typeface="Microsoft Yi Baiti"/>
  421. <a:font script="Tibt" typeface="Microsoft Himalaya"/>
  422. <a:font script="Thaa" typeface="MV Boli"/>
  423. <a:font script="Deva" typeface="Mangal"/>
  424. <a:font script="Telu" typeface="Gautami"/>
  425. <a:font script="Taml" typeface="Latha"/>
  426. <a:font script="Syrc" typeface="Estrangelo Edessa"/>
  427. <a:font script="Orya" typeface="Kalinga"/>
  428. <a:font script="Mlym" typeface="Kartika"/>
  429. <a:font script="Laoo" typeface="DokChampa"/>
  430. <a:font script="Sinh" typeface="Iskoola Pota"/>
  431. <a:font script="Mong" typeface="Mongolian Baiti"/>
  432. <a:font script="Viet" typeface="Times New Roman"/>
  433. <a:font script="Uigh" typeface="Microsoft Uighur"/>
  434. <a:font script="Geor" typeface="Sylfaen"/>
  435. </a:majorFont>
  436. <a:minorFont>
  437. <a:latin typeface="Calibri"/>
  438. <a:ea typeface=""/>
  439. <a:cs typeface=""/>
  440. <a:font script="Jpan" typeface="MS Pゴシック"/>
  441. <a:font script="Hang" typeface="맑은 고딕"/>
  442. <a:font script="Hans" typeface="宋体"/>
  443. <a:font script="Hant" typeface="新細明體"/>
  444. <a:font script="Arab" typeface="Arial"/>
  445. <a:font script="Hebr" typeface="Arial"/>
  446. <a:font script="Thai" typeface="Tahoma"/>
  447. <a:font script="Ethi" typeface="Nyala"/>
  448. <a:font script="Beng" typeface="Vrinda"/>
  449. <a:font script="Gujr" typeface="Shruti"/>
  450. <a:font script="Khmr" typeface="DaunPenh"/>
  451. <a:font script="Knda" typeface="Tunga"/>
  452. <a:font script="Guru" typeface="Raavi"/>
  453. <a:font script="Cans" typeface="Euphemia"/>
  454. <a:font script="Cher" typeface="Plantagenet Cherokee"/>
  455. <a:font script="Yiii" typeface="Microsoft Yi Baiti"/>
  456. <a:font script="Tibt" typeface="Microsoft Himalaya"/>
  457. <a:font script="Thaa" typeface="MV Boli"/>
  458. <a:font script="Deva" typeface="Mangal"/>
  459. <a:font script="Telu" typeface="Gautami"/>
  460. <a:font script="Taml" typeface="Latha"/>
  461. <a:font script="Syrc" typeface="Estrangelo Edessa"/>
  462. <a:font script="Orya" typeface="Kalinga"/>
  463. <a:font script="Mlym" typeface="Kartika"/>
  464. <a:font script="Laoo" typeface="DokChampa"/>
  465. <a:font script="Sinh" typeface="Iskoola Pota"/>
  466. <a:font script="Mong" typeface="Mongolian Baiti"/>
  467. <a:font script="Viet" typeface="Arial"/>
  468. <a:font script="Uigh" typeface="Microsoft Uighur"/>
  469. <a:font script="Geor" typeface="Sylfaen"/>
  470. </a:minorFont>
  471. </a:fontScheme>
  472. <a:fmtScheme name="Office">
  473. <a:fillStyleLst>
  474. <a:solidFill>
  475. <a:schemeClr val="phClr"/>
  476. </a:solidFill>
  477. <a:gradFill rotWithShape="1">
  478. <a:gsLst>
  479. <a:gs pos="0">
  480. <a:schemeClr val="phClr">
  481. <a:tint val="50000"/>
  482. <a:satMod val="300000"/>
  483. </a:schemeClr>
  484. </a:gs>
  485. <a:gs pos="35000">
  486. <a:schemeClr val="phClr">
  487. <a:tint val="37000"/>
  488. <a:satMod val="300000"/>
  489. </a:schemeClr>
  490. </a:gs>
  491. <a:gs pos="100000">
  492. <a:schemeClr val="phClr">
  493. <a:tint val="15000"/>
  494. <a:satMod val="350000"/>
  495. </a:schemeClr>
  496. </a:gs>
  497. </a:gsLst>
  498. <a:lin ang="16200000" scaled="1"/>
  499. </a:gradFill>
  500. <a:gradFill rotWithShape="1">
  501. <a:gsLst>
  502. <a:gs pos="0">
  503. <a:schemeClr val="phClr">
  504. <a:tint val="100000"/>
  505. <a:shade val="100000"/>
  506. <a:satMod val="130000"/>
  507. </a:schemeClr>
  508. </a:gs>
  509. <a:gs pos="100000">
  510. <a:schemeClr val="phClr">
  511. <a:tint val="50000"/>
  512. <a:shade val="100000"/>
  513. <a:satMod val="350000"/>
  514. </a:schemeClr>
  515. </a:gs>
  516. </a:gsLst>
  517. <a:lin ang="16200000" scaled="0"/>
  518. </a:gradFill>
  519. </a:fillStyleLst>
  520. <a:lnStyleLst>
  521. <a:ln w="9525" cap="flat" cmpd="sng" algn="ctr">
  522. <a:solidFill>
  523. <a:schemeClr val="phClr">
  524. <a:shade val="95000"/>
  525. <a:satMod val="105000"/>
  526. </a:schemeClr>
  527. </a:solidFill>
  528. <a:prstDash val="solid"/>
  529. </a:ln>
  530. <a:ln w="25400" cap="flat" cmpd="sng" algn="ctr">
  531. <a:solidFill>
  532. <a:schemeClr val="phClr"/>
  533. </a:solidFill>
  534. <a:prstDash val="solid"/>
  535. </a:ln>
  536. <a:ln w="38100" cap="flat" cmpd="sng" algn="ctr">
  537. <a:solidFill>
  538. <a:schemeClr val="phClr"/>
  539. </a:solidFill>
  540. <a:prstDash val="solid"/>
  541. </a:ln>
  542. </a:lnStyleLst>
  543. <a:effectStyleLst>
  544. <a:effectStyle>
  545. <a:effectLst>
  546. <a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0">
  547. <a:srgbClr val="000000">
  548. <a:alpha val="38000"/>
  549. </a:srgbClr>
  550. </a:outerShdw>
  551. </a:effectLst>
  552. </a:effectStyle>
  553. <a:effectStyle>
  554. <a:effectLst>
  555. <a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0">
  556. <a:srgbClr val="000000">
  557. <a:alpha val="35000"/>
  558. </a:srgbClr>
  559. </a:outerShdw>
  560. </a:effectLst>
  561. </a:effectStyle>
  562. <a:effectStyle>
  563. <a:effectLst>
  564. <a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0">
  565. <a:srgbClr val="000000">
  566. <a:alpha val="35000"/>
  567. </a:srgbClr>
  568. </a:outerShdw>
  569. </a:effectLst>
  570. <a:scene3d>
  571. <a:camera prst="orthographicFront">
  572. <a:rot lat="0" lon="0" rev="0"/>
  573. </a:camera>
  574. <a:lightRig rig="threePt" dir="t">
  575. <a:rot lat="0" lon="0" rev="1200000"/>
  576. </a:lightRig>
  577. </a:scene3d>
  578. <a:sp3d>
  579. <a:bevelT w="63500" h="25400"/>
  580. </a:sp3d>
  581. </a:effectStyle>
  582. </a:effectStyleLst>
  583. <a:bgFillStyleLst>
  584. <a:solidFill>
  585. <a:schemeClr val="phClr"/>
  586. </a:solidFill>
  587. <a:gradFill rotWithShape="1">
  588. <a:gsLst>
  589. <a:gs pos="0">
  590. <a:schemeClr val="phClr">
  591. <a:tint val="40000"/>
  592. <a:satMod val="350000"/>
  593. </a:schemeClr>
  594. </a:gs>
  595. <a:gs pos="40000">
  596. <a:schemeClr val="phClr">
  597. <a:tint val="45000"/>
  598. <a:shade val="99000"/>
  599. <a:satMod val="350000"/>
  600. </a:schemeClr>
  601. </a:gs>
  602. <a:gs pos="100000">
  603. <a:schemeClr val="phClr">
  604. <a:shade val="20000"/>
  605. <a:satMod val="255000"/>
  606. </a:schemeClr>
  607. </a:gs>
  608. </a:gsLst>
  609. <a:path path="circle">
  610. <a:fillToRect l="50000" t="-80000" r="50000" b="180000"/>
  611. </a:path>
  612. </a:gradFill>
  613. <a:gradFill rotWithShape="1">
  614. <a:gsLst>
  615. <a:gs pos="0">
  616. <a:schemeClr val="phClr">
  617. <a:tint val="80000"/>
  618. <a:satMod val="300000"/>
  619. </a:schemeClr>
  620. </a:gs>
  621. <a:gs pos="100000">
  622. <a:schemeClr val="phClr">
  623. <a:shade val="30000"/>
  624. <a:satMod val="200000"/>
  625. </a:schemeClr>
  626. </a:gs>
  627. </a:gsLst>
  628. <a:path path="circle">
  629. <a:fillToRect l="50000" t="50000" r="50000" b="50000"/>
  630. </a:path>
  631. </a:gradFill>
  632. </a:bgFillStyleLst>
  633. </a:fmtScheme>
  634. </a:themeElements>
  635. <a:objectDefaults>
  636. <a:spDef>
  637. <a:spPr/>
  638. <a:bodyPr/>
  639. <a:lstStyle/>
  640. <a:style>
  641. <a:lnRef idx="1">
  642. <a:schemeClr val="accent1"/>
  643. </a:lnRef>
  644. <a:fillRef idx="3">
  645. <a:schemeClr val="accent1"/>
  646. </a:fillRef>
  647. <a:effectRef idx="2">
  648. <a:schemeClr val="accent1"/>
  649. </a:effectRef>
  650. <a:fontRef idx="minor">
  651. <a:schemeClr val="lt1"/>
  652. </a:fontRef>
  653. </a:style>
  654. </a:spDef>
  655. <a:lnDef>
  656. <a:spPr/>
  657. <a:bodyPr/>
  658. <a:lstStyle/>
  659. <a:style>
  660. <a:lnRef idx="2">
  661. <a:schemeClr val="accent1"/>
  662. </a:lnRef>
  663. <a:fillRef idx="0">
  664. <a:schemeClr val="accent1"/>
  665. </a:fillRef>
  666. <a:effectRef idx="1">
  667. <a:schemeClr val="accent1"/>
  668. </a:effectRef>
  669. <a:fontRef idx="minor">
  670. <a:schemeClr val="tx1"/>
  671. </a:fontRef>
  672. </a:style>
  673. </a:lnDef>
  674. </a:objectDefaults>
  675. <a:extraClrSchemeLst/>
  676. </a:theme>`
  677. c.Assert(parts["xl/theme/theme1.xml"], Equals, expectedTheme)
  678. // sharedStrings.xml
  679. expectedXLSXSST := `<?xml version="1.0" encoding="UTF-8"?>
  680. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="1" uniqueCount="1"><si><t>A cell!</t></si></sst>`
  681. c.Assert(parts["xl/sharedStrings.xml"], Equals, expectedXLSXSST)
  682. // workbook.xml.rels
  683. expectedXLSXWorkbookRels := `<?xml version="1.0" encoding="UTF-8"?>
  684. <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="worksheets/sheet1.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"></Relationship><Relationship Id="rId2" Target="worksheets/sheet2.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"></Relationship><Relationship Id="rId3" Target="sharedStrings.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"></Relationship><Relationship Id="rId4" Target="theme/theme1.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"></Relationship><Relationship Id="rId5" Target="styles.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"></Relationship></Relationships>`
  685. c.Assert(parts["xl/_rels/workbook.xml.rels"], Equals, expectedXLSXWorkbookRels)
  686. // workbook.xml
  687. // Note that the following XML snippet is just pasted in here to correspond to the hack
  688. // added in file.go to support Apple Numbers so the test passes.
  689. // `xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"`
  690. expectedWorkbook := `<?xml version="1.0" encoding="UTF-8"?>
  691. <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><fileVersion appName="Go XLSX"></fileVersion><workbookPr showObjects="all" date1904="false"></workbookPr><workbookProtection></workbookProtection><bookViews><workbookView showHorizontalScroll="true" showVerticalScroll="true" showSheetTabs="true" tabRatio="204" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"></workbookView></bookViews><sheets><sheet name="MySheet" sheetId="1" r:id="rId1" state="visible"></sheet><sheet name="AnotherSheet" sheetId="2" r:id="rId2" state="visible"></sheet></sheets><definedNames></definedNames><calcPr iterateCount="100" refMode="A1" iterateDelta="0.001"></calcPr></workbook>`
  692. c.Assert(parts["xl/workbook.xml"], Equals, expectedWorkbook)
  693. // [Content_Types].xml
  694. expectedContentTypes := `<?xml version="1.0" encoding="UTF-8"?>
  695. <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"></Override><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"></Override><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"></Override><Override PartName="/xl/_rels/workbook.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"></Override><Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"></Override><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"></Override><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"></Override><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"></Override><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"></Override><Override PartName="/xl/worksheets/sheet2.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"></Override><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"></Default><Default Extension="xml" ContentType="application/xml"></Default></Types>`
  696. c.Assert(parts["[Content_Types].xml"], Equals, expectedContentTypes)
  697. // styles.xml
  698. //
  699. // For now we only allow simple string data in the
  700. // spreadsheet. Style support will follow.
  701. expectedStyles := `<?xml version="1.0" encoding="UTF-8"?>
  702. <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><fonts count="1"><font><sz val="12"/><name val="Verdana"/><family val="0"/><charset val="0"/></font></fonts><fills count="2"><fill><patternFill patternType="none"><fgColor rgb="FFFFFFFF"/><bgColor rgb="00000000"/></patternFill></fill><fill><patternFill patternType="lightGray"/></fill></fills><borders count="1"><border><left style="none"></left><right style="none"></right><top style="none"></top><bottom style="none"></bottom></border></borders><cellXfs count="2"><xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0"><alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/></xf><xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0"><alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/></xf></cellXfs></styleSheet>`
  703. c.Assert(parts["xl/styles.xml"], Equals, expectedStyles)
  704. }
  705. // We can save a File as a valid XLSX file at a given path.
  706. func (l *FileSuite) TestSaveFile(c *C) {
  707. var tmpPath string = c.MkDir()
  708. var f *File
  709. f = NewFile()
  710. sheet1, _ := f.AddSheet("MySheet")
  711. row1 := sheet1.AddRow()
  712. cell1 := row1.AddCell()
  713. cell1.Value = "A cell!"
  714. sheet2, _ := f.AddSheet("AnotherSheet")
  715. row2 := sheet2.AddRow()
  716. cell2 := row2.AddCell()
  717. cell2.Value = "A cell!"
  718. xlsxPath := filepath.Join(tmpPath, "TestSaveFile.xlsx")
  719. err := f.Save(xlsxPath)
  720. c.Assert(err, IsNil)
  721. // Let's eat our own dog food
  722. xlsxFile, err := OpenFile(xlsxPath)
  723. c.Assert(err, IsNil)
  724. c.Assert(xlsxFile, NotNil)
  725. c.Assert(len(xlsxFile.Sheets), Equals, 2)
  726. sheet1, ok := xlsxFile.Sheet["MySheet"]
  727. c.Assert(ok, Equals, true)
  728. c.Assert(len(sheet1.Rows), Equals, 1)
  729. row1 = sheet1.Rows[0]
  730. c.Assert(len(row1.Cells), Equals, 1)
  731. cell1 = row1.Cells[0]
  732. c.Assert(cell1.Value, Equals, "A cell!")
  733. }
  734. type SliceReaderSuite struct{}
  735. var _ = Suite(&SliceReaderSuite{})
  736. func (s *SliceReaderSuite) TestFileToSlice(c *C) {
  737. output, err := FileToSlice("./testdocs/testfile.xlsx")
  738. c.Assert(err, IsNil)
  739. fileToSliceCheckOutput(c, output)
  740. }
  741. func (s *SliceReaderSuite) TestFileToSliceMissingCol(c *C) {
  742. // Test xlsx file with the A column removed
  743. _, err := FileToSlice("./testdocs/testFileToSlice.xlsx")
  744. c.Assert(err, IsNil)
  745. }
  746. func (s *SliceReaderSuite) TestFileObjToSlice(c *C) {
  747. f, err := OpenFile("./testdocs/testfile.xlsx")
  748. output, err := f.ToSlice()
  749. c.Assert(err, IsNil)
  750. fileToSliceCheckOutput(c, output)
  751. }
  752. func fileToSliceCheckOutput(c *C, output [][][]string) {
  753. c.Assert(len(output), Equals, 3)
  754. c.Assert(len(output[0]), Equals, 2)
  755. c.Assert(len(output[0][0]), Equals, 2)
  756. c.Assert(output[0][0][0], Equals, "Foo")
  757. c.Assert(output[0][0][1], Equals, "Bar")
  758. c.Assert(len(output[0][1]), Equals, 2)
  759. c.Assert(output[0][1][0], Equals, "Baz")
  760. c.Assert(output[0][1][1], Equals, "Quuk")
  761. c.Assert(len(output[1]), Equals, 0)
  762. c.Assert(len(output[2]), Equals, 0)
  763. }
  764. func (l *FileSuite) TestReadWorkbookWithTypes(c *C) {
  765. var xlsxFile *File
  766. var err error
  767. xlsxFile, err = OpenFile("./testdocs/testcelltypes.xlsx")
  768. c.Assert(err, IsNil)
  769. c.Assert(len(xlsxFile.Sheets), Equals, 1)
  770. sheet := xlsxFile.Sheet["Sheet1"]
  771. c.Assert(len(sheet.Rows), Equals, 8)
  772. c.Assert(len(sheet.Rows[0].Cells), Equals, 2)
  773. // string 1
  774. c.Assert(sheet.Rows[0].Cells[0].Type(), Equals, CellTypeString)
  775. if val, err := sheet.Rows[0].Cells[0].FormattedValue(); err != nil {
  776. c.Error(err)
  777. } else {
  778. c.Assert(val, Equals, "hello world")
  779. }
  780. // string 2
  781. c.Assert(sheet.Rows[1].Cells[0].Type(), Equals, CellTypeString)
  782. if val, err := sheet.Rows[1].Cells[0].FormattedValue(); err != nil {
  783. c.Error(err)
  784. } else {
  785. c.Assert(val, Equals, "日本語")
  786. }
  787. // integer
  788. c.Assert(sheet.Rows[2].Cells[0].Type(), Equals, CellTypeNumeric)
  789. intValue, _ := sheet.Rows[2].Cells[0].Int()
  790. c.Assert(intValue, Equals, 12345)
  791. // float
  792. c.Assert(sheet.Rows[3].Cells[0].Type(), Equals, CellTypeNumeric)
  793. floatValue, _ := sheet.Rows[3].Cells[0].Float()
  794. c.Assert(floatValue, Equals, 1.024)
  795. // Now it can't detect date
  796. c.Assert(sheet.Rows[4].Cells[0].Type(), Equals, CellTypeNumeric)
  797. intValue, _ = sheet.Rows[4].Cells[0].Int()
  798. c.Assert(intValue, Equals, 40543)
  799. // bool
  800. c.Assert(sheet.Rows[5].Cells[0].Type(), Equals, CellTypeBool)
  801. c.Assert(sheet.Rows[5].Cells[0].Bool(), Equals, true)
  802. // formula
  803. c.Assert(sheet.Rows[6].Cells[0].Type(), Equals, CellTypeFormula)
  804. c.Assert(sheet.Rows[6].Cells[0].Formula(), Equals, "10+20")
  805. c.Assert(sheet.Rows[6].Cells[0].Value, Equals, "30")
  806. // error
  807. c.Assert(sheet.Rows[7].Cells[0].Type(), Equals, CellTypeError)
  808. c.Assert(sheet.Rows[7].Cells[0].Formula(), Equals, "10/0")
  809. c.Assert(sheet.Rows[7].Cells[0].Value, Equals, "#DIV/0!")
  810. }
  811. func (s *SliceReaderSuite) TestFileWithEmptyRows(c *C) {
  812. f, err := OpenFile("./testdocs/empty_rows.xlsx")
  813. c.Assert(err, IsNil)
  814. sheet, ok := f.Sheet["EmptyRows"]
  815. c.Assert(ok, Equals, true)
  816. if val, err := sheet.Cell(0, 0).FormattedValue(); err != nil {
  817. c.Error(err)
  818. } else {
  819. c.Assert(val, Equals, "")
  820. }
  821. if val, err := sheet.Cell(2, 0).FormattedValue(); err != nil {
  822. c.Error(err)
  823. } else {
  824. c.Assert(val, Equals, "A3")
  825. }
  826. }
  827. func (s *SliceReaderSuite) TestFileWithEmptyCols(c *C) {
  828. f, err := OpenFile("./testdocs/empty_rows.xlsx")
  829. c.Assert(err, IsNil)
  830. sheet, ok := f.Sheet["EmptyCols"]
  831. c.Assert(ok, Equals, true)
  832. if val, err := sheet.Cell(0, 0).FormattedValue(); err != nil {
  833. c.Error(err)
  834. } else {
  835. c.Assert(val, Equals, "")
  836. }
  837. if val, err := sheet.Cell(0, 2).FormattedValue(); err != nil {
  838. c.Error(err)
  839. } else {
  840. c.Assert(val, Equals, "C1")
  841. }
  842. }