file_test.go 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. package xlsx
  2. import (
  3. "encoding/xml"
  4. "io"
  5. "os"
  6. "path/filepath"
  7. . "gopkg.in/check.v1"
  8. )
  9. // ReaderAtCounter wraps a ReaderAt and counts the number of bytes that are read out of it
  10. type ReaderAtCounter struct {
  11. readerAt io.ReaderAt
  12. bytesRead int
  13. }
  14. var _ io.ReaderAt = &ReaderAtCounter{}
  15. // NewReaderAtCounter creates a ReaderAtCounter by opening the file name, and provides the size which is needed for
  16. // opening as XLSX.
  17. func NewReaderAtCounter(name string) (*ReaderAtCounter, int64, error) {
  18. f, err := os.Open(name)
  19. if err != nil {
  20. return nil, -1, err
  21. }
  22. fi, err := f.Stat()
  23. if err != nil {
  24. f.Close()
  25. return nil, -1, err
  26. }
  27. readerAtCounter := &ReaderAtCounter{
  28. readerAt: f,
  29. }
  30. return readerAtCounter, fi.Size(), nil
  31. }
  32. func (r *ReaderAtCounter) ReadAt(p []byte, off int64) (n int, err error) {
  33. n, err = r.readerAt.ReadAt(p, off)
  34. r.bytesRead += n
  35. return n, err
  36. }
  37. func (r *ReaderAtCounter) GetBytesRead() int {
  38. return r.bytesRead
  39. }
  40. type FileSuite struct{}
  41. var _ = Suite(&FileSuite{})
  42. // Test we can correctly open a XSLX file and return a xlsx.File
  43. // struct.
  44. func (l *FileSuite) TestOpenFile(c *C) {
  45. var xlsxFile *File
  46. var err error
  47. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  48. c.Assert(err, IsNil)
  49. c.Assert(xlsxFile, NotNil)
  50. }
  51. func (l *FileSuite) TestPartialReadsWithFewSharedStringsOnlyPartiallyReads(c *C) {
  52. // This test verifies that a large file is only partially read when using a small row limit.
  53. // This file is 11,228,530 bytes, but only 14,020 bytes get read out when using a row limit of 10.
  54. // I'm specifying a limit of 20,000 to prevent test flakiness if the bytes read fluctuates with small code changes.
  55. rowLimit := 10
  56. // It is possible that readLimit will need to be increased by a small amount in the future, but do not increase it
  57. // to anywhere near a significant amount of 11 million. We're testing that this number is low, to ensure that partial
  58. // reads are fast.
  59. readLimit := 20 * 1000
  60. reader, size, err := NewReaderAtCounter("testdocs/large_sheet_no_shared_strings_no_dimension_tag.xlsx")
  61. if err != nil {
  62. c.Fatal(err)
  63. }
  64. file, err := OpenReaderAtWithRowLimit(reader, size, rowLimit)
  65. if reader.bytesRead > readLimit {
  66. // If this test begins failing, do not increase readLimit dramatically. Instead investigate why the number of
  67. // bytes read went up and fix this issue.
  68. c.Errorf("Reading %v rows from a sheet with ~31,000 rows and few shared strings read %v bytes, must read less than %v bytes", rowLimit, reader.bytesRead, readLimit)
  69. }
  70. if len(file.Sheets[0].Rows) != rowLimit {
  71. c.Errorf("Expected sheet to have %v rows, but found %v rows", rowLimit, len(file.Sheets[0].Rows))
  72. }
  73. }
  74. func (l *FileSuite) TestPartialReadsWithLargeSharedStringsOnlyPartiallyReads(c *C) {
  75. // This test verifies that a large file is only partially read when using a small row limit.
  76. // This file is 7,055,632 bytes, but only 1,092,839 bytes get read out when using a row limit of 10.
  77. // I'm specifying a limit of 1.2 MB to prevent test flakiness if the bytes read fluctuates with small code changes.
  78. // The reason that this test has a much larger limit than TestPartialReadsWithFewSharedStringsOnlyPartiallyReads
  79. // is that this file has a Shared Strings file that is a little over 1 MB.
  80. rowLimit := 10
  81. // It is possible that readLimit will need to be increased by a small amount in the future, but do not increase it
  82. // to anywhere near a significant amount of 7 million. We're testing that this number is low, to ensure that partial
  83. // reads are fast.
  84. readLimit := int(1.2 * 1000 * 1000)
  85. reader, size, err := NewReaderAtCounter("testdocs/large_sheet_large_sharedstrings_dimension_tag.xlsx")
  86. if err != nil {
  87. c.Fatal(err)
  88. }
  89. file, err := OpenReaderAtWithRowLimit(reader, size, rowLimit)
  90. if reader.bytesRead > readLimit {
  91. // If this test begins failing, do not increase readLimit dramatically. Instead investigate why the number of
  92. // bytes read went up and fix this issue.
  93. c.Errorf("Reading %v rows from a sheet with ~31,000 rows and a large shared strings read %v bytes, must read less than %v bytes", rowLimit, reader.bytesRead, readLimit)
  94. }
  95. // This is testing that the sheet was truncated, but it is also testing that the dimension tag was ignored.
  96. // If the dimension tag is not correctly ignored, there will be 10 rows of the data, plus ~31k empty rows tacked on.
  97. if len(file.Sheets[0].Rows) != rowLimit {
  98. c.Errorf("Expected sheet to have %v rows, but found %v rows", rowLimit, len(file.Sheets[0].Rows))
  99. }
  100. }
  101. func (l *FileSuite) TestPartialReadsWithFewerRowsThanRequested(c *C) {
  102. rowLimit := 10
  103. file, err := OpenFileWithRowLimit("testdocs/testfile.xlsx", rowLimit)
  104. if err != nil {
  105. c.Fatal(err)
  106. }
  107. if len(file.Sheets[0].Rows) != 2 {
  108. c.Errorf("Expected sheet to have %v rows, but found %v rows", 2, len(file.Sheets[0].Rows))
  109. }
  110. }
  111. func (l *FileSuite) TestOpenFileWithoutStyleAndSharedStrings(c *C) {
  112. var xlsxFile *File
  113. var error error
  114. xlsxFile, error = OpenFile("./testdocs/noStylesAndSharedStringsTest.xlsx")
  115. c.Assert(error, IsNil)
  116. c.Assert(xlsxFile, NotNil)
  117. }
  118. func (l *FileSuite) TestOpenFileWithChartsheet(c *C) {
  119. xlsxFile, error := OpenFile("./testdocs/testchartsheet.xlsx")
  120. c.Assert(error, IsNil)
  121. c.Assert(xlsxFile, NotNil)
  122. }
  123. // Test that we can correctly extract a reference table from the
  124. // sharedStrings.xml file embedded in the XLSX file and return a
  125. // reference table of string values from it.
  126. func (l *FileSuite) TestReadSharedStringsFromZipFile(c *C) {
  127. var xlsxFile *File
  128. var err error
  129. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  130. c.Assert(err, IsNil)
  131. c.Assert(xlsxFile.referenceTable, NotNil)
  132. }
  133. // Helper function used to test contents of a given xlsxXf against
  134. // expectations.
  135. func testXf(c *C, result, expected *xlsxXf) {
  136. c.Assert(result.ApplyAlignment, Equals, expected.ApplyAlignment)
  137. c.Assert(result.ApplyBorder, Equals, expected.ApplyBorder)
  138. c.Assert(result.ApplyFont, Equals, expected.ApplyFont)
  139. c.Assert(result.ApplyFill, Equals, expected.ApplyFill)
  140. c.Assert(result.ApplyProtection, Equals, expected.ApplyProtection)
  141. c.Assert(result.BorderId, Equals, expected.BorderId)
  142. c.Assert(result.FillId, Equals, expected.FillId)
  143. c.Assert(result.FontId, Equals, expected.FontId)
  144. c.Assert(result.NumFmtId, Equals, expected.NumFmtId)
  145. }
  146. // We can correctly extract a style table from the style.xml file
  147. // embedded in the XLSX file and return a styles struct from it.
  148. func (l *FileSuite) TestReadStylesFromZipFile(c *C) {
  149. var xlsxFile *File
  150. var err error
  151. var fontCount, fillCount, borderCount, cellStyleXfCount, cellXfCount int
  152. var font xlsxFont
  153. var fill xlsxFill
  154. var border xlsxBorder
  155. var xf xlsxXf
  156. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  157. c.Assert(err, IsNil)
  158. c.Assert(xlsxFile.styles, NotNil)
  159. fontCount = len(xlsxFile.styles.Fonts.Font)
  160. c.Assert(fontCount, Equals, 4)
  161. font = xlsxFile.styles.Fonts.Font[0]
  162. c.Assert(font.Sz.Val, Equals, "11")
  163. c.Assert(font.Name.Val, Equals, "Calibri")
  164. fillCount = xlsxFile.styles.Fills.Count
  165. c.Assert(fillCount, Equals, 3)
  166. fill = xlsxFile.styles.Fills.Fill[2]
  167. c.Assert(fill.PatternFill.PatternType, Equals, "solid")
  168. borderCount = xlsxFile.styles.Borders.Count
  169. c.Assert(borderCount, Equals, 2)
  170. border = xlsxFile.styles.Borders.Border[1]
  171. c.Assert(border.Left.Style, Equals, "thin")
  172. c.Assert(border.Right.Style, Equals, "thin")
  173. c.Assert(border.Top.Style, Equals, "thin")
  174. c.Assert(border.Bottom.Style, Equals, "thin")
  175. cellStyleXfCount = xlsxFile.styles.CellStyleXfs.Count
  176. c.Assert(cellStyleXfCount, Equals, 20)
  177. xf = xlsxFile.styles.CellStyleXfs.Xf[0]
  178. expectedXf := &xlsxXf{
  179. ApplyAlignment: true,
  180. ApplyBorder: true,
  181. ApplyFont: true,
  182. ApplyFill: false,
  183. ApplyProtection: true,
  184. BorderId: 0,
  185. FillId: 0,
  186. FontId: 0,
  187. NumFmtId: 164}
  188. testXf(c, &xf, expectedXf)
  189. c.Assert(xf.Alignment, NotNil)
  190. c.Assert(xf.Alignment.Horizontal, Equals, "general")
  191. c.Assert(xf.Alignment.Indent, Equals, 0)
  192. c.Assert(xf.Alignment.ShrinkToFit, Equals, false)
  193. c.Assert(xf.Alignment.TextRotation, Equals, 0)
  194. c.Assert(xf.Alignment.Vertical, Equals, "bottom")
  195. c.Assert(xf.Alignment.WrapText, Equals, false)
  196. cellXfCount = xlsxFile.styles.CellXfs.Count
  197. c.Assert(cellXfCount, Equals, 3)
  198. xf = xlsxFile.styles.CellXfs.Xf[0]
  199. expectedXf = &xlsxXf{
  200. ApplyAlignment: false,
  201. ApplyBorder: false,
  202. ApplyFont: false,
  203. ApplyFill: false,
  204. ApplyProtection: false,
  205. BorderId: 0,
  206. FillId: 0,
  207. FontId: 0,
  208. NumFmtId: 164}
  209. testXf(c, &xf, expectedXf)
  210. }
  211. // We can correctly extract a map of relationship Ids to the worksheet files in
  212. // which they are contained from the XLSX file.
  213. func (l *FileSuite) TestReadWorkbookRelationsFromZipFile(c *C) {
  214. var xlsxFile *File
  215. var err error
  216. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  217. c.Assert(err, IsNil)
  218. c.Assert(len(xlsxFile.Sheets), Equals, 3)
  219. sheet, ok := xlsxFile.Sheet["Tabelle1"]
  220. c.Assert(ok, Equals, true)
  221. c.Assert(sheet, NotNil)
  222. }
  223. // Style information is correctly extracted from the zipped XLSX file.
  224. func (l *FileSuite) TestGetStyleFromZipFile(c *C) {
  225. var xlsxFile *File
  226. var err error
  227. var style *Style
  228. var val string
  229. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  230. c.Assert(err, IsNil)
  231. sheetCount := len(xlsxFile.Sheets)
  232. c.Assert(sheetCount, Equals, 3)
  233. tabelle1 := xlsxFile.Sheet["Tabelle1"]
  234. row0 := tabelle1.Rows[0]
  235. cellFoo := row0.Cells[0]
  236. style = cellFoo.GetStyle()
  237. if val, err = cellFoo.FormattedValue(); err != nil {
  238. c.Error(err)
  239. }
  240. c.Assert(val, Equals, "Foo")
  241. c.Assert(style.Fill.BgColor, Equals, "FF33CCCC")
  242. c.Assert(style.ApplyFill, Equals, false)
  243. c.Assert(style.ApplyFont, Equals, true)
  244. row1 := tabelle1.Rows[1]
  245. cellQuuk := row1.Cells[1]
  246. style = cellQuuk.GetStyle()
  247. if val, err = cellQuuk.FormattedValue(); err != nil {
  248. c.Error(err)
  249. }
  250. c.Assert(val, Equals, "Quuk")
  251. c.Assert(style.Border.Left, Equals, "thin")
  252. c.Assert(style.ApplyBorder, Equals, true)
  253. cellBar := row0.Cells[1]
  254. if val, err = cellBar.FormattedValue(); err != nil {
  255. c.Error(err)
  256. }
  257. c.Assert(val, Equals, "Bar")
  258. c.Assert(cellBar.GetStyle().Fill.BgColor, Equals, "")
  259. }
  260. // Test we can create a File object from scratch
  261. func (l *FileSuite) TestCreateFile(c *C) {
  262. var xlsxFile *File
  263. xlsxFile = NewFile()
  264. c.Assert(xlsxFile, NotNil)
  265. }
  266. // Test that when we open a real XLSX file we create xlsx.Sheet
  267. // objects for the sheets inside the file and that these sheets are
  268. // themselves correct.
  269. func (l *FileSuite) TestCreateSheet(c *C) {
  270. var xlsxFile *File
  271. var err error
  272. var sheet *Sheet
  273. var row *Row
  274. xlsxFile, err = OpenFile("./testdocs/testfile.xlsx")
  275. c.Assert(err, IsNil)
  276. c.Assert(xlsxFile, NotNil)
  277. sheetLen := len(xlsxFile.Sheets)
  278. c.Assert(sheetLen, Equals, 3)
  279. sheet = xlsxFile.Sheet["Tabelle1"]
  280. rowLen := len(sheet.Rows)
  281. c.Assert(rowLen, Equals, 2)
  282. row = sheet.Rows[0]
  283. c.Assert(len(row.Cells), Equals, 2)
  284. cell := row.Cells[0]
  285. if val, err := cell.FormattedValue(); err != nil {
  286. c.Error(err)
  287. } else {
  288. c.Assert(val, Equals, "Foo")
  289. }
  290. }
  291. // Test that we can add a sheet to a File
  292. func (l *FileSuite) TestAddSheet(c *C) {
  293. var f *File
  294. f = NewFile()
  295. sheet, err := f.AddSheet("MySheet")
  296. c.Assert(err, IsNil)
  297. c.Assert(sheet, NotNil)
  298. c.Assert(len(f.Sheets), Equals, 1)
  299. c.Assert(f.Sheet["MySheet"], Equals, sheet)
  300. }
  301. // Test that AddSheet returns an error if you try to add two sheets with the same name
  302. func (l *FileSuite) TestAddSheetWithDuplicateName(c *C) {
  303. f := NewFile()
  304. _, err := f.AddSheet("MySheet")
  305. c.Assert(err, IsNil)
  306. _, err = f.AddSheet("MySheet")
  307. c.Assert(err, ErrorMatches, "duplicate sheet name 'MySheet'.")
  308. }
  309. // Test that AddSheet returns an error if you try to add sheet with name as empty string
  310. func (l *FileSuite) TestAddSheetWithEmptyName(c *C) {
  311. f := NewFile()
  312. _, err := f.AddSheet("")
  313. c.Assert(err, ErrorMatches, "sheet name must be 31 or fewer characters long. It is currently '0' characters long")
  314. }
  315. // Test that we can append a sheet to a File
  316. func (l *FileSuite) TestAppendSheet(c *C) {
  317. var f *File
  318. f = NewFile()
  319. s := Sheet{}
  320. sheet, err := f.AppendSheet(s, "MySheet")
  321. c.Assert(err, IsNil)
  322. c.Assert(sheet, NotNil)
  323. c.Assert(len(f.Sheets), Equals, 1)
  324. c.Assert(f.Sheet["MySheet"], Equals, sheet)
  325. }
  326. // Test that AppendSheet returns an error if you try to add two sheets with the same name
  327. func (l *FileSuite) TestAppendSheetWithDuplicateName(c *C) {
  328. f := NewFile()
  329. s := Sheet{}
  330. _, err := f.AppendSheet(s, "MySheet")
  331. c.Assert(err, IsNil)
  332. _, err = f.AppendSheet(s, "MySheet")
  333. c.Assert(err, ErrorMatches, "duplicate sheet name 'MySheet'.")
  334. }
  335. // Test that we can read & create a 31 rune sheet name
  336. func (l *FileSuite) TestMaxSheetNameLength(c *C) {
  337. // Open a genuine xlsx created by Microsoft Excel 2007
  338. xlsxFile, err := OpenFile("./testdocs/max_sheet_name_length.xlsx")
  339. c.Assert(err, IsNil)
  340. c.Assert(xlsxFile, NotNil)
  341. c.Assert(xlsxFile.Sheets[0].Name, Equals, "αααααβββββγγγγγδδδδδεεεεεζζζζζη")
  342. // Create a new file with the same sheet name
  343. f := NewFile()
  344. s, err := f.AddSheet(xlsxFile.Sheets[0].Name)
  345. c.Assert(err, IsNil)
  346. c.Assert(s.Name, Equals, "αααααβββββγγγγγδδδδδεεεεεζζζζζη")
  347. }
  348. // Test that we can get the Nth sheet
  349. func (l *FileSuite) TestNthSheet(c *C) {
  350. var f *File
  351. f = NewFile()
  352. sheet, _ := f.AddSheet("MySheet")
  353. sheetByIndex := f.Sheets[0]
  354. sheetByName := f.Sheet["MySheet"]
  355. c.Assert(sheetByIndex, NotNil)
  356. c.Assert(sheetByIndex, Equals, sheet)
  357. c.Assert(sheetByIndex, Equals, sheetByName)
  358. }
  359. // Test invalid sheet name characters
  360. func (l *FileSuite) TestInvalidSheetNameCharacters(c *C) {
  361. f := NewFile()
  362. for _, invalidChar := range []string{":", "\\", "/", "?", "*", "[", "]"} {
  363. _, err := f.AddSheet(invalidChar)
  364. c.Assert(err, NotNil)
  365. }
  366. }
  367. // Test that we can create a Workbook and marshal it to XML.
  368. func (l *FileSuite) TestMarshalWorkbook(c *C) {
  369. var f *File
  370. f = NewFile()
  371. f.AddSheet("MyFirstSheet")
  372. f.AddSheet("MySecondSheet")
  373. workbook := f.makeWorkbook()
  374. workbook.Sheets.Sheet[0] = xlsxSheet{
  375. Name: "MyFirstSheet",
  376. SheetId: "1",
  377. Id: "rId1",
  378. State: "visible"}
  379. workbook.Sheets.Sheet[1] = xlsxSheet{
  380. Name: "MySecondSheet",
  381. SheetId: "2",
  382. Id: "rId2",
  383. State: "visible"}
  384. expectedWorkbook := `<?xml version="1.0" encoding="UTF-8"?>
  385. <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>`
  386. output, err := xml.Marshal(workbook)
  387. c.Assert(err, IsNil)
  388. outputStr := replaceRelationshipsNameSpace(string(output))
  389. stringOutput := xml.Header + outputStr
  390. c.Assert(stringOutput, Equals, expectedWorkbook)
  391. }
  392. // Test that we can marshall a File to a collection of xml files
  393. func (l *FileSuite) TestMarshalFile(c *C) {
  394. var f *File
  395. f = NewFile()
  396. sheet1, _ := f.AddSheet("MySheet")
  397. row1 := sheet1.AddRow()
  398. cell1 := row1.AddCell()
  399. cell1.SetString("A cell!")
  400. sheet2, _ := f.AddSheet("AnotherSheet")
  401. row2 := sheet2.AddRow()
  402. cell2 := row2.AddCell()
  403. cell2.SetString("A cell!")
  404. parts, err := f.MarshallParts()
  405. c.Assert(err, IsNil)
  406. c.Assert(len(parts), Equals, 11)
  407. // sheets
  408. expectedSheet1 := `<?xml version="1.0" encoding="UTF-8"?>
  409. <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><sheetData><row r="1"><c r="A1" 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>`
  410. c.Assert(parts["xl/worksheets/sheet1.xml"], Equals, expectedSheet1)
  411. expectedSheet2 := `<?xml version="1.0" encoding="UTF-8"?>
  412. <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><sheetData><row r="1"><c r="A1" 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>`
  413. c.Assert(parts["xl/worksheets/sheet2.xml"], Equals, expectedSheet2)
  414. // .rels.xml
  415. expectedRels := `<?xml version="1.0" encoding="UTF-8"?>
  416. <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  417. <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
  418. <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
  419. <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
  420. </Relationships>`
  421. c.Assert(parts["_rels/.rels"], Equals, expectedRels)
  422. // app.xml
  423. expectedApp := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  424. <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  425. <TotalTime>0</TotalTime>
  426. <Application>Go XLSX</Application>
  427. </Properties>`
  428. c.Assert(parts["docProps/app.xml"], Equals, expectedApp)
  429. // core.xml
  430. expectedCore := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  431. <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>`
  432. c.Assert(parts["docProps/core.xml"], Equals, expectedCore)
  433. // theme1.xml
  434. expectedTheme := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  435. <a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office-Design">
  436. <a:themeElements>
  437. <a:clrScheme name="Office">
  438. <a:dk1>
  439. <a:sysClr val="windowText" lastClr="000000"/>
  440. </a:dk1>
  441. <a:lt1>
  442. <a:sysClr val="window" lastClr="FFFFFF"/>
  443. </a:lt1>
  444. <a:dk2>
  445. <a:srgbClr val="1F497D"/>
  446. </a:dk2>
  447. <a:lt2>
  448. <a:srgbClr val="EEECE1"/>
  449. </a:lt2>
  450. <a:accent1>
  451. <a:srgbClr val="4F81BD"/>
  452. </a:accent1>
  453. <a:accent2>
  454. <a:srgbClr val="C0504D"/>
  455. </a:accent2>
  456. <a:accent3>
  457. <a:srgbClr val="9BBB59"/>
  458. </a:accent3>
  459. <a:accent4>
  460. <a:srgbClr val="8064A2"/>
  461. </a:accent4>
  462. <a:accent5>
  463. <a:srgbClr val="4BACC6"/>
  464. </a:accent5>
  465. <a:accent6>
  466. <a:srgbClr val="F79646"/>
  467. </a:accent6>
  468. <a:hlink>
  469. <a:srgbClr val="0000FF"/>
  470. </a:hlink>
  471. <a:folHlink>
  472. <a:srgbClr val="800080"/>
  473. </a:folHlink>
  474. </a:clrScheme>
  475. <a:fontScheme name="Office">
  476. <a:majorFont>
  477. <a:latin typeface="Cambria"/>
  478. <a:ea typeface=""/>
  479. <a:cs typeface=""/>
  480. <a:font script="Jpan" typeface="MS Pゴシック"/>
  481. <a:font script="Hang" typeface="맑은 고딕"/>
  482. <a:font script="Hans" typeface="宋体"/>
  483. <a:font script="Hant" typeface="新細明體"/>
  484. <a:font script="Arab" typeface="Times New Roman"/>
  485. <a:font script="Hebr" typeface="Times New Roman"/>
  486. <a:font script="Thai" typeface="Tahoma"/>
  487. <a:font script="Ethi" typeface="Nyala"/>
  488. <a:font script="Beng" typeface="Vrinda"/>
  489. <a:font script="Gujr" typeface="Shruti"/>
  490. <a:font script="Khmr" typeface="MoolBoran"/>
  491. <a:font script="Knda" typeface="Tunga"/>
  492. <a:font script="Guru" typeface="Raavi"/>
  493. <a:font script="Cans" typeface="Euphemia"/>
  494. <a:font script="Cher" typeface="Plantagenet Cherokee"/>
  495. <a:font script="Yiii" typeface="Microsoft Yi Baiti"/>
  496. <a:font script="Tibt" typeface="Microsoft Himalaya"/>
  497. <a:font script="Thaa" typeface="MV Boli"/>
  498. <a:font script="Deva" typeface="Mangal"/>
  499. <a:font script="Telu" typeface="Gautami"/>
  500. <a:font script="Taml" typeface="Latha"/>
  501. <a:font script="Syrc" typeface="Estrangelo Edessa"/>
  502. <a:font script="Orya" typeface="Kalinga"/>
  503. <a:font script="Mlym" typeface="Kartika"/>
  504. <a:font script="Laoo" typeface="DokChampa"/>
  505. <a:font script="Sinh" typeface="Iskoola Pota"/>
  506. <a:font script="Mong" typeface="Mongolian Baiti"/>
  507. <a:font script="Viet" typeface="Times New Roman"/>
  508. <a:font script="Uigh" typeface="Microsoft Uighur"/>
  509. <a:font script="Geor" typeface="Sylfaen"/>
  510. </a:majorFont>
  511. <a:minorFont>
  512. <a:latin typeface="Arial"/>
  513. <a:ea typeface=""/>
  514. <a:cs typeface=""/>
  515. <a:font script="Jpan" typeface="MS Pゴシック"/>
  516. <a:font script="Hang" typeface="맑은 고딕"/>
  517. <a:font script="Hans" typeface="宋体"/>
  518. <a:font script="Hant" typeface="新細明體"/>
  519. <a:font script="Arab" typeface="Arial"/>
  520. <a:font script="Hebr" typeface="Arial"/>
  521. <a:font script="Thai" typeface="Tahoma"/>
  522. <a:font script="Ethi" typeface="Nyala"/>
  523. <a:font script="Beng" typeface="Vrinda"/>
  524. <a:font script="Gujr" typeface="Shruti"/>
  525. <a:font script="Khmr" typeface="DaunPenh"/>
  526. <a:font script="Knda" typeface="Tunga"/>
  527. <a:font script="Guru" typeface="Raavi"/>
  528. <a:font script="Cans" typeface="Euphemia"/>
  529. <a:font script="Cher" typeface="Plantagenet Cherokee"/>
  530. <a:font script="Yiii" typeface="Microsoft Yi Baiti"/>
  531. <a:font script="Tibt" typeface="Microsoft Himalaya"/>
  532. <a:font script="Thaa" typeface="MV Boli"/>
  533. <a:font script="Deva" typeface="Mangal"/>
  534. <a:font script="Telu" typeface="Gautami"/>
  535. <a:font script="Taml" typeface="Latha"/>
  536. <a:font script="Syrc" typeface="Estrangelo Edessa"/>
  537. <a:font script="Orya" typeface="Kalinga"/>
  538. <a:font script="Mlym" typeface="Kartika"/>
  539. <a:font script="Laoo" typeface="DokChampa"/>
  540. <a:font script="Sinh" typeface="Iskoola Pota"/>
  541. <a:font script="Mong" typeface="Mongolian Baiti"/>
  542. <a:font script="Viet" typeface="Arial"/>
  543. <a:font script="Uigh" typeface="Microsoft Uighur"/>
  544. <a:font script="Geor" typeface="Sylfaen"/>
  545. </a:minorFont>
  546. </a:fontScheme>
  547. <a:fmtScheme name="Office">
  548. <a:fillStyleLst>
  549. <a:solidFill>
  550. <a:schemeClr val="phClr"/>
  551. </a:solidFill>
  552. <a:gradFill rotWithShape="1">
  553. <a:gsLst>
  554. <a:gs pos="0">
  555. <a:schemeClr val="phClr">
  556. <a:tint val="50000"/>
  557. <a:satMod val="300000"/>
  558. </a:schemeClr>
  559. </a:gs>
  560. <a:gs pos="35000">
  561. <a:schemeClr val="phClr">
  562. <a:tint val="37000"/>
  563. <a:satMod val="300000"/>
  564. </a:schemeClr>
  565. </a:gs>
  566. <a:gs pos="100000">
  567. <a:schemeClr val="phClr">
  568. <a:tint val="15000"/>
  569. <a:satMod val="350000"/>
  570. </a:schemeClr>
  571. </a:gs>
  572. </a:gsLst>
  573. <a:lin ang="16200000" scaled="1"/>
  574. </a:gradFill>
  575. <a:gradFill rotWithShape="1">
  576. <a:gsLst>
  577. <a:gs pos="0">
  578. <a:schemeClr val="phClr">
  579. <a:tint val="100000"/>
  580. <a:shade val="100000"/>
  581. <a:satMod val="130000"/>
  582. </a:schemeClr>
  583. </a:gs>
  584. <a:gs pos="100000">
  585. <a:schemeClr val="phClr">
  586. <a:tint val="50000"/>
  587. <a:shade val="100000"/>
  588. <a:satMod val="350000"/>
  589. </a:schemeClr>
  590. </a:gs>
  591. </a:gsLst>
  592. <a:lin ang="16200000" scaled="0"/>
  593. </a:gradFill>
  594. </a:fillStyleLst>
  595. <a:lnStyleLst>
  596. <a:ln w="9525" cap="flat" cmpd="sng" algn="ctr">
  597. <a:solidFill>
  598. <a:schemeClr val="phClr">
  599. <a:shade val="95000"/>
  600. <a:satMod val="105000"/>
  601. </a:schemeClr>
  602. </a:solidFill>
  603. <a:prstDash val="solid"/>
  604. </a:ln>
  605. <a:ln w="25400" cap="flat" cmpd="sng" algn="ctr">
  606. <a:solidFill>
  607. <a:schemeClr val="phClr"/>
  608. </a:solidFill>
  609. <a:prstDash val="solid"/>
  610. </a:ln>
  611. <a:ln w="38100" cap="flat" cmpd="sng" algn="ctr">
  612. <a:solidFill>
  613. <a:schemeClr val="phClr"/>
  614. </a:solidFill>
  615. <a:prstDash val="solid"/>
  616. </a:ln>
  617. </a:lnStyleLst>
  618. <a:effectStyleLst>
  619. <a:effectStyle>
  620. <a:effectLst>
  621. <a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0">
  622. <a:srgbClr val="000000">
  623. <a:alpha val="38000"/>
  624. </a:srgbClr>
  625. </a:outerShdw>
  626. </a:effectLst>
  627. </a:effectStyle>
  628. <a:effectStyle>
  629. <a:effectLst>
  630. <a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0">
  631. <a:srgbClr val="000000">
  632. <a:alpha val="35000"/>
  633. </a:srgbClr>
  634. </a:outerShdw>
  635. </a:effectLst>
  636. </a:effectStyle>
  637. <a:effectStyle>
  638. <a:effectLst>
  639. <a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0">
  640. <a:srgbClr val="000000">
  641. <a:alpha val="35000"/>
  642. </a:srgbClr>
  643. </a:outerShdw>
  644. </a:effectLst>
  645. <a:scene3d>
  646. <a:camera prst="orthographicFront">
  647. <a:rot lat="0" lon="0" rev="0"/>
  648. </a:camera>
  649. <a:lightRig rig="threePt" dir="t">
  650. <a:rot lat="0" lon="0" rev="1200000"/>
  651. </a:lightRig>
  652. </a:scene3d>
  653. <a:sp3d>
  654. <a:bevelT w="63500" h="25400"/>
  655. </a:sp3d>
  656. </a:effectStyle>
  657. </a:effectStyleLst>
  658. <a:bgFillStyleLst>
  659. <a:solidFill>
  660. <a:schemeClr val="phClr"/>
  661. </a:solidFill>
  662. <a:gradFill rotWithShape="1">
  663. <a:gsLst>
  664. <a:gs pos="0">
  665. <a:schemeClr val="phClr">
  666. <a:tint val="40000"/>
  667. <a:satMod val="350000"/>
  668. </a:schemeClr>
  669. </a:gs>
  670. <a:gs pos="40000">
  671. <a:schemeClr val="phClr">
  672. <a:tint val="45000"/>
  673. <a:shade val="99000"/>
  674. <a:satMod val="350000"/>
  675. </a:schemeClr>
  676. </a:gs>
  677. <a:gs pos="100000">
  678. <a:schemeClr val="phClr">
  679. <a:shade val="20000"/>
  680. <a:satMod val="255000"/>
  681. </a:schemeClr>
  682. </a:gs>
  683. </a:gsLst>
  684. <a:path path="circle">
  685. <a:fillToRect l="50000" t="-80000" r="50000" b="180000"/>
  686. </a:path>
  687. </a:gradFill>
  688. <a:gradFill rotWithShape="1">
  689. <a:gsLst>
  690. <a:gs pos="0">
  691. <a:schemeClr val="phClr">
  692. <a:tint val="80000"/>
  693. <a:satMod val="300000"/>
  694. </a:schemeClr>
  695. </a:gs>
  696. <a:gs pos="100000">
  697. <a:schemeClr val="phClr">
  698. <a:shade val="30000"/>
  699. <a:satMod val="200000"/>
  700. </a:schemeClr>
  701. </a:gs>
  702. </a:gsLst>
  703. <a:path path="circle">
  704. <a:fillToRect l="50000" t="50000" r="50000" b="50000"/>
  705. </a:path>
  706. </a:gradFill>
  707. </a:bgFillStyleLst>
  708. </a:fmtScheme>
  709. </a:themeElements>
  710. <a:objectDefaults>
  711. <a:spDef>
  712. <a:spPr/>
  713. <a:bodyPr/>
  714. <a:lstStyle/>
  715. <a:style>
  716. <a:lnRef idx="1">
  717. <a:schemeClr val="accent1"/>
  718. </a:lnRef>
  719. <a:fillRef idx="3">
  720. <a:schemeClr val="accent1"/>
  721. </a:fillRef>
  722. <a:effectRef idx="2">
  723. <a:schemeClr val="accent1"/>
  724. </a:effectRef>
  725. <a:fontRef idx="minor">
  726. <a:schemeClr val="lt1"/>
  727. </a:fontRef>
  728. </a:style>
  729. </a:spDef>
  730. <a:lnDef>
  731. <a:spPr/>
  732. <a:bodyPr/>
  733. <a:lstStyle/>
  734. <a:style>
  735. <a:lnRef idx="2">
  736. <a:schemeClr val="accent1"/>
  737. </a:lnRef>
  738. <a:fillRef idx="0">
  739. <a:schemeClr val="accent1"/>
  740. </a:fillRef>
  741. <a:effectRef idx="1">
  742. <a:schemeClr val="accent1"/>
  743. </a:effectRef>
  744. <a:fontRef idx="minor">
  745. <a:schemeClr val="tx1"/>
  746. </a:fontRef>
  747. </a:style>
  748. </a:lnDef>
  749. </a:objectDefaults>
  750. <a:extraClrSchemeLst/>
  751. </a:theme>`
  752. c.Assert(parts["xl/theme/theme1.xml"], Equals, expectedTheme)
  753. // sharedStrings.xml
  754. expectedXLSXSST := `<?xml version="1.0" encoding="UTF-8"?>
  755. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="1" uniqueCount="1"><si><t>A cell!</t></si></sst>`
  756. c.Assert(parts["xl/sharedStrings.xml"], Equals, expectedXLSXSST)
  757. // workbook.xml.rels
  758. expectedXLSXWorkbookRels := `<?xml version="1.0" encoding="UTF-8"?>
  759. <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>`
  760. c.Assert(parts["xl/_rels/workbook.xml.rels"], Equals, expectedXLSXWorkbookRels)
  761. // workbook.xml
  762. // Note that the following XML snippet is just pasted in here to correspond to the hack
  763. // added in file.go to support Apple Numbers so the test passes.
  764. // `xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"`
  765. expectedWorkbook := `<?xml version="1.0" encoding="UTF-8"?>
  766. <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>`
  767. c.Assert(parts["xl/workbook.xml"], Equals, expectedWorkbook)
  768. // [Content_Types].xml
  769. expectedContentTypes := `<?xml version="1.0" encoding="UTF-8"?>
  770. <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>`
  771. c.Assert(parts["[Content_Types].xml"], Equals, expectedContentTypes)
  772. // styles.xml
  773. //
  774. // For now we only allow simple string data in the
  775. // spreadsheet. Style support will follow.
  776. expectedStyles := `<?xml version="1.0" encoding="UTF-8"?>
  777. <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><borders count="1"><border><left style="none"></left><right style="none"></right><top style="none"></top><bottom style="none"></bottom></border></borders><cellStyleXfs count="1"><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></cellStyleXfs><cellXfs count="1"><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>`
  778. c.Assert(parts["xl/styles.xml"], Equals, expectedStyles)
  779. }
  780. // We can save a File as a valid XLSX file at a given path.
  781. func (l *FileSuite) TestSaveFile(c *C) {
  782. var tmpPath string = c.MkDir()
  783. var f *File
  784. f = NewFile()
  785. sheet1, _ := f.AddSheet("MySheet")
  786. row1 := sheet1.AddRow()
  787. cell1 := row1.AddCell()
  788. cell1.Value = "A cell!"
  789. sheet2, _ := f.AddSheet("AnotherSheet")
  790. row2 := sheet2.AddRow()
  791. cell2 := row2.AddCell()
  792. cell2.Value = "A cell!"
  793. xlsxPath := filepath.Join(tmpPath, "TestSaveFile.xlsx")
  794. err := f.Save(xlsxPath)
  795. c.Assert(err, IsNil)
  796. // Let's eat our own dog food
  797. xlsxFile, err := OpenFile(xlsxPath)
  798. c.Assert(err, IsNil)
  799. c.Assert(xlsxFile, NotNil)
  800. c.Assert(len(xlsxFile.Sheets), Equals, 2)
  801. sheet1, ok := xlsxFile.Sheet["MySheet"]
  802. c.Assert(ok, Equals, true)
  803. c.Assert(len(sheet1.Rows), Equals, 1)
  804. row1 = sheet1.Rows[0]
  805. c.Assert(len(row1.Cells), Equals, 1)
  806. cell1 = row1.Cells[0]
  807. c.Assert(cell1.Value, Equals, "A cell!")
  808. }
  809. type SliceReaderSuite struct{}
  810. var _ = Suite(&SliceReaderSuite{})
  811. func (s *SliceReaderSuite) TestFileToSlice(c *C) {
  812. output, err := FileToSlice("./testdocs/testfile.xlsx")
  813. c.Assert(err, IsNil)
  814. fileToSliceCheckOutput(c, output)
  815. }
  816. func (s *SliceReaderSuite) TestFileToSliceMissingCol(c *C) {
  817. // Test xlsx file with the A column removed
  818. _, err := FileToSlice("./testdocs/testFileToSlice.xlsx")
  819. c.Assert(err, IsNil)
  820. }
  821. func (s *SliceReaderSuite) TestFileObjToSlice(c *C) {
  822. f, err := OpenFile("./testdocs/testfile.xlsx")
  823. output, err := f.ToSlice()
  824. c.Assert(err, IsNil)
  825. fileToSliceCheckOutput(c, output)
  826. }
  827. func fileToSliceCheckOutput(c *C, output [][][]string) {
  828. c.Assert(len(output), Equals, 3)
  829. c.Assert(len(output[0]), Equals, 2)
  830. c.Assert(len(output[0][0]), Equals, 2)
  831. c.Assert(output[0][0][0], Equals, "Foo")
  832. c.Assert(output[0][0][1], Equals, "Bar")
  833. c.Assert(len(output[0][1]), Equals, 2)
  834. c.Assert(output[0][1][0], Equals, "Baz")
  835. c.Assert(output[0][1][1], Equals, "Quuk")
  836. c.Assert(len(output[1]), Equals, 0)
  837. c.Assert(len(output[2]), Equals, 0)
  838. }
  839. func (s *SliceReaderSuite) TestFileToSliceUnmerged(c *C) {
  840. output, err := FileToSliceUnmerged("./testdocs/testfile.xlsx")
  841. c.Assert(err, IsNil)
  842. fileToSliceCheckOutput(c, output)
  843. // merged cells
  844. output, err = FileToSliceUnmerged("./testdocs/merged_cells.xlsx")
  845. c.Assert(err, IsNil)
  846. c.Assert(output[0][6][2], Equals, "Happy New Year!")
  847. c.Assert(output[0][6][1], Equals, "Happy New Year!")
  848. c.Assert(output[0][1][0], Equals, "01.01.2016")
  849. c.Assert(output[0][2][0], Equals, "01.01.2016")
  850. }
  851. func (l *FileSuite) TestReadWorkbookWithTypes(c *C) {
  852. var xlsxFile *File
  853. var err error
  854. xlsxFile, err = OpenFile("./testdocs/testcelltypes.xlsx")
  855. c.Assert(err, IsNil)
  856. c.Assert(len(xlsxFile.Sheets), Equals, 1)
  857. sheet := xlsxFile.Sheet["Sheet1"]
  858. c.Assert(len(sheet.Rows), Equals, 8)
  859. c.Assert(len(sheet.Rows[0].Cells), Equals, 2)
  860. // string 1
  861. c.Assert(sheet.Rows[0].Cells[0].Type(), Equals, CellTypeString)
  862. if val, err := sheet.Rows[0].Cells[0].FormattedValue(); err != nil {
  863. c.Error(err)
  864. } else {
  865. c.Assert(val, Equals, "hello world")
  866. }
  867. // string 2
  868. c.Assert(sheet.Rows[1].Cells[0].Type(), Equals, CellTypeString)
  869. if val, err := sheet.Rows[1].Cells[0].FormattedValue(); err != nil {
  870. c.Error(err)
  871. } else {
  872. c.Assert(val, Equals, "日本語")
  873. }
  874. // integer
  875. c.Assert(sheet.Rows[2].Cells[0].Type(), Equals, CellTypeNumeric)
  876. intValue, _ := sheet.Rows[2].Cells[0].Int()
  877. c.Assert(intValue, Equals, 12345)
  878. // float
  879. c.Assert(sheet.Rows[3].Cells[0].Type(), Equals, CellTypeNumeric)
  880. floatValue, _ := sheet.Rows[3].Cells[0].Float()
  881. c.Assert(floatValue, Equals, 1.024)
  882. // Now it can't detect date
  883. c.Assert(sheet.Rows[4].Cells[0].Type(), Equals, CellTypeNumeric)
  884. intValue, _ = sheet.Rows[4].Cells[0].Int()
  885. c.Assert(intValue, Equals, 40543)
  886. // bool
  887. c.Assert(sheet.Rows[5].Cells[0].Type(), Equals, CellTypeBool)
  888. c.Assert(sheet.Rows[5].Cells[0].Bool(), Equals, true)
  889. // formula
  890. c.Assert(sheet.Rows[6].Cells[0].Type(), Equals, CellTypeNumeric)
  891. c.Assert(sheet.Rows[6].Cells[0].Formula(), Equals, "10+20")
  892. c.Assert(sheet.Rows[6].Cells[0].Value, Equals, "30")
  893. // error
  894. c.Assert(sheet.Rows[7].Cells[0].Type(), Equals, CellTypeError)
  895. c.Assert(sheet.Rows[7].Cells[0].Formula(), Equals, "10/0")
  896. c.Assert(sheet.Rows[7].Cells[0].Value, Equals, "#DIV/0!")
  897. }
  898. func (s *SliceReaderSuite) TestFileWithEmptyRows(c *C) {
  899. f, err := OpenFile("./testdocs/empty_rows.xlsx")
  900. c.Assert(err, IsNil)
  901. sheet, ok := f.Sheet["EmptyRows"]
  902. c.Assert(ok, Equals, true)
  903. if val, err := sheet.Cell(0, 0).FormattedValue(); err != nil {
  904. c.Error(err)
  905. } else {
  906. c.Assert(val, Equals, "")
  907. }
  908. if val, err := sheet.Cell(2, 0).FormattedValue(); err != nil {
  909. c.Error(err)
  910. } else {
  911. c.Assert(val, Equals, "A3")
  912. }
  913. }
  914. func (s *SliceReaderSuite) TestFileWithEmptyCols(c *C) {
  915. f, err := OpenFile("./testdocs/empty_rows.xlsx")
  916. c.Assert(err, IsNil)
  917. sheet, ok := f.Sheet["EmptyCols"]
  918. c.Assert(ok, Equals, true)
  919. if val, err := sheet.Cell(0, 0).FormattedValue(); err != nil {
  920. c.Error(err)
  921. } else {
  922. c.Assert(val, Equals, "")
  923. }
  924. if val, err := sheet.Cell(0, 2).FormattedValue(); err != nil {
  925. c.Error(err)
  926. } else {
  927. c.Assert(val, Equals, "C1")
  928. }
  929. }