package xlsx
import (
"bytes"
"encoding/xml"
// "strconv"
"strings"
. "gopkg.in/check.v1"
)
type LibSuite struct {}
var _ = Suite(&LibSuite{})
// Test we can correctly open a XSLX file and return a xlsx.File
// struct.
func (l *LibSuite) TestOpenFile(c *C) {
var xlsxFile *File
var error error
xlsxFile, error = OpenFile("testfile.xlsx")
c.Assert(error, IsNil)
c.Assert(xlsxFile, NotNil)
}
// Test that when we open a real XLSX file we create xlsx.Sheet
// objects for the sheets inside the file and that these sheets are
// themselves correct.
func (l *LibSuite) TestCreateSheet(c *C) {
var xlsxFile *File
var err error
var sheet *Sheet
var row *Row
xlsxFile, err = OpenFile("testfile.xlsx")
c.Assert(err, IsNil)
c.Assert(xlsxFile, NotNil)
sheetLen := len(xlsxFile.Sheets)
c.Assert(sheetLen, Equals, 3)
sheet = xlsxFile.Sheets[0]
rowLen := len(sheet.Rows)
c.Assert(rowLen, Equals, 2)
row = sheet.Rows[0]
c.Assert(len(row.Cells), Equals, 2)
cell := row.Cells[0]
cellstring := cell.String()
c.Assert(cellstring, Equals, "Foo")
}
// Test that GetStyle correctly converts the xlsxStyle.Fonts.
func (l *LibSuite) TestGetStyleWithFonts(c *C) {
var cell *Cell
var style *Style
var xStyles *xlsxStyles
var fonts []xlsxFont
var cellXfs []xlsxXf
fonts = make([]xlsxFont, 1)
fonts[0] = xlsxFont{
Sz: xlsxVal{Val: "10"},
Name: xlsxVal{Val: "Calibra"}}
cellXfs = make([]xlsxXf, 1)
cellXfs[0] = xlsxXf{ApplyFont: true, FontId: 0}
xStyles = &xlsxStyles{Fonts: fonts, CellXfs: cellXfs}
cell = &Cell{Value: "123", styleIndex: 1, styles: xStyles}
style = cell.GetStyle()
c.Assert(style, NotNil)
c.Assert(style.Font.Size, Equals, 10)
c.Assert(style.Font.Name, Equals, "Calibra")
}
// Test that GetStyle correctly converts the xlsxStyle.Fills.
func (l *LibSuite) TestGetStyleWithFills(c *C) {
var cell *Cell
var style *Style
var xStyles *xlsxStyles
var fills []xlsxFill
var cellXfs []xlsxXf
fills = make([]xlsxFill, 1)
fills[0] = xlsxFill{
PatternFill: xlsxPatternFill{
PatternType: "solid",
FgColor: xlsxColor{RGB: "FF000000"},
BgColor: xlsxColor{RGB: "00FF0000"}}}
cellXfs = make([]xlsxXf, 1)
cellXfs[0] = xlsxXf{ApplyFill: true, FillId: 0}
xStyles = &xlsxStyles{Fills: fills, CellXfs: cellXfs}
cell = &Cell{Value: "123", styleIndex: 1, styles: xStyles}
style = cell.GetStyle()
fill := style.Fill
c.Assert(fill.PatternType, Equals, "solid")
c.Assert(fill.BgColor, Equals, "00FF0000")
c.Assert(fill.FgColor, Equals, "FF000000")
}
// Test that GetStyle correctly converts the xlsxStyle.Borders.
func (l *LibSuite) TestGetStyleWithBorders(c *C) {
var cell *Cell
var style *Style
var xStyles *xlsxStyles
var borders []xlsxBorder
var cellXfs []xlsxXf
borders = make([]xlsxBorder, 1)
borders[0] = xlsxBorder{
Left: xlsxLine{Style: "thin"},
Right: xlsxLine{Style: "thin"},
Top: xlsxLine{Style: "thin"},
Bottom: xlsxLine{Style: "thin"}}
cellXfs = make([]xlsxXf, 1)
cellXfs[0] = xlsxXf{ApplyBorder: true, BorderId: 0}
xStyles = &xlsxStyles{Borders: borders, CellXfs: cellXfs}
cell = &Cell{Value: "123", styleIndex: 1, styles: xStyles}
style = cell.GetStyle()
border := style.Border
c.Assert(border.Left, Equals, "thin")
c.Assert(border.Right, Equals, "thin")
c.Assert(border.Top, Equals, "thin")
c.Assert(border.Bottom, Equals, "thin")
}
// Test that we can correctly extract a reference table from the
// sharedStrings.xml file embedded in the XLSX file and return a
// reference table of string values from it.
func (l *LibSuite) TestReadSharedStringsFromZipFile(c *C) {
var xlsxFile *File
var err error
xlsxFile, err = OpenFile("testfile.xlsx")
c.Assert(err, IsNil)
c.Assert(xlsxFile.referenceTable, NotNil)
}
// Helper function used to test contents of a given xlsxXf against
// expectations.
func testXf(c *C, result, expected *xlsxXf) {
c.Assert(result.ApplyAlignment, Equals, expected.ApplyAlignment)
c.Assert(result.ApplyBorder, Equals, expected.ApplyBorder)
c.Assert(result.ApplyFont, Equals, expected.ApplyFont)
c.Assert(result.ApplyFill, Equals, expected.ApplyFill)
c.Assert(result.ApplyProtection, Equals, expected.ApplyProtection)
c.Assert(result.BorderId, Equals, expected.BorderId)
c.Assert(result.FillId, Equals, expected.FillId)
c.Assert(result.FontId, Equals, expected.FontId)
c.Assert(result.NumFmtId, Equals, expected.NumFmtId)
}
// We can correctly extract a style table from the style.xml file
// embedded in the XLSX file and return a styles struct from it.
func (l *LibSuite) TestReadStylesFromZipFile(c *C) {
var xlsxFile *File
var err error
var fontCount, fillCount, borderCount, cellStyleXfCount, cellXfCount int
var font xlsxFont
var fill xlsxFill
var border xlsxBorder
var xf xlsxXf
xlsxFile, err = OpenFile("testfile.xlsx")
c.Assert(err, IsNil)
c.Assert(xlsxFile.styles, NotNil)
fontCount = len(xlsxFile.styles.Fonts)
c.Assert(fontCount, Equals, 4)
font = xlsxFile.styles.Fonts[0]
c.Assert(font.Sz.Val, Equals, "11")
c.Assert(font.Name.Val, Equals, "Calibri")
fillCount = len(xlsxFile.styles.Fills)
c.Assert(fillCount, Equals, 3)
fill = xlsxFile.styles.Fills[2]
c.Assert(fill.PatternFill.PatternType, Equals, "solid")
borderCount = len(xlsxFile.styles.Borders)
c.Assert(borderCount, Equals, 2)
border = xlsxFile.styles.Borders[1]
c.Assert(border.Left.Style, Equals, "thin")
c.Assert(border.Right.Style, Equals, "thin")
c.Assert(border.Top.Style, Equals, "thin")
c.Assert(border.Bottom.Style, Equals, "thin")
cellStyleXfCount = len(xlsxFile.styles.CellStyleXfs)
c.Assert(cellStyleXfCount, Equals, 20)
xf = xlsxFile.styles.CellStyleXfs[0]
expectedXf := &xlsxXf{
ApplyAlignment: true,
ApplyBorder: true,
ApplyFont: true,
ApplyFill: false,
ApplyProtection: true,
BorderId: 0,
FillId: 0,
FontId: 0,
NumFmtId: 164}
testXf(c, &xf, expectedXf)
cellXfCount = len(xlsxFile.styles.CellXfs)
c.Assert(cellXfCount, Equals, 3)
xf = xlsxFile.styles.CellXfs[0]
expectedXf = &xlsxXf{
ApplyAlignment: false,
ApplyBorder: false,
ApplyFont: false,
ApplyFill: false,
ApplyProtection: false,
BorderId: 0,
FillId: 0,
FontId: 0,
NumFmtId: 164}
testXf(c, &xf, expectedXf)
}
// We can correctly extract a map of relationship Ids to the worksheet files in
// which they are contained from the XLSX file.
func (l *LibSuite) TestReadWorkbookRelationsFromZipFile(c *C) {
var xlsxFile *File
var err error
xlsxFile, err = OpenFile("testfile.xlsx")
c.Assert(err, IsNil)
sheetCount := len(xlsxFile.Sheet)
c.Assert(sheetCount, Equals, 3)
}
// which they are contained from the XLSX file, even when the
// worksheet files have arbitrary, non-numeric names.
func (l *LibSuite) TestReadWorkbookRelationsFromZipFileWithFunnyNames(c *C) {
var xlsxFile *File
var err error
xlsxFile, err = OpenFile("testrels.xlsx")
c.Assert(err, IsNil)
sheetCount := len(xlsxFile.Sheet)
c.Assert(sheetCount, Equals, 2)
bob := xlsxFile.Sheet["Bob"]
row1 := bob.Rows[0]
cell1 := row1.Cells[0]
c.Assert(cell1.String(), Equals, "I am Bob")
}
func (l *LibSuite) TestLettersToNumeric(c *C) {
cases := map[string]int{"A": 0, "G": 6, "z": 25, "AA": 26, "Az": 51,
"BA": 52, "Bz": 77, "ZA": 26*26 + 0, "ZZ": 26*26 + 25,
"AAA": 26*26 + 26 + 0, "AMI": 1022}
for input, ans := range cases {
output := lettersToNumeric(input)
c.Assert(output, Equals, ans)
}
}
func (l *LibSuite) TestLetterOnlyMapFunction(c *C) {
var input string = "ABC123"
var output string = strings.Map(letterOnlyMapF, input)
c.Assert(output, Equals, "ABC")
input = "abc123"
output = strings.Map(letterOnlyMapF, input)
c.Assert(output, Equals, "ABC")
}
func (l *LibSuite) TestIntOnlyMapFunction(c *C) {
var input string = "ABC123"
var output string = strings.Map(intOnlyMapF, input)
c.Assert(output, Equals, "123")
}
func (l *LibSuite) TestGetCoordsFromCellIDString(c *C) {
var cellIDString string = "A3"
var x, y int
var err error
x, y, err = getCoordsFromCellIDString(cellIDString)
c.Assert(err, IsNil)
c.Assert(x, Equals, 0)
c.Assert(y, Equals, 2)
}
func (l *LibSuite) TestGetMaxMinFromDimensionRef(c *C) {
var dimensionRef string = "A1:B2"
var minx, miny, maxx, maxy int
var err error
minx, miny, maxx, maxy, err = getMaxMinFromDimensionRef(dimensionRef)
c.Assert(err, IsNil)
c.Assert(minx, Equals, 0)
c.Assert(miny, Equals, 0)
c.Assert(maxx, Equals, 1)
c.Assert(maxy, Equals, 1)
}
func (l *LibSuite) TestGetRangeFromString(c *C) {
var rangeString string
var lower, upper int
var err error
rangeString = "1:3"
lower, upper, err = getRangeFromString(rangeString)
c.Assert(err, IsNil)
c.Assert(lower, Equals, 1)
c.Assert(upper, Equals, 3)
}
func (l *LibSuite) TestMakeRowFromSpan(c *C) {
var rangeString string
var row *Row
var length int
rangeString = "1:3"
row = makeRowFromSpan(rangeString)
length = len(row.Cells)
c.Assert(length, Equals, 3)
rangeString = "5:7" // Note - we ignore lower bound!
row = makeRowFromSpan(rangeString)
length = len(row.Cells)
c.Assert(length, Equals, 7)
rangeString = "1:1"
row = makeRowFromSpan(rangeString)
length = len(row.Cells)
c.Assert(length, Equals, 1)
}
func (l *LibSuite) TestReadRowsFromSheet(c *C) {
var sharedstringsXML = bytes.NewBufferString(`
Foo
Bar
Baz
Quuk
`)
var sheetxml = bytes.NewBufferString(`
0
1
2
3
`)
worksheet := new(xlsxWorksheet)
err := xml.NewDecoder(sheetxml).Decode(worksheet)
c.Assert(err, IsNil)
sst := new(xlsxSST)
err = xml.NewDecoder(sharedstringsXML).Decode(sst)
c.Assert(err, IsNil)
file := new(File)
file.referenceTable = MakeSharedStringRefTable(sst)
rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
c.Assert(maxRows, Equals, 2)
c.Assert(maxCols, Equals, 2)
row := rows[0]
c.Assert(len(row.Cells), Equals, 2)
cell1 := row.Cells[0]
c.Assert(cell1.String(), Equals, "Foo")
cell2 := row.Cells[1]
c.Assert(cell2.String(), Equals, "Bar")
}
func (l *LibSuite) TestReadRowsFromSheetWithLeadingEmptyRows(c *C) {
var sharedstringsXML = bytes.NewBufferString(`
ABCDEF`)
var sheetxml = bytes.NewBufferString(`
0
1
`)
worksheet := new(xlsxWorksheet)
err := xml.NewDecoder(sheetxml).Decode(worksheet)
c.Assert(err, IsNil)
sst := new(xlsxSST)
err = xml.NewDecoder(sharedstringsXML).Decode(sst)
c.Assert(err, IsNil)
file := new(File)
file.referenceTable = MakeSharedStringRefTable(sst)
_, maxCols, maxRows := readRowsFromSheet(worksheet, file)
c.Assert(maxRows, Equals, 2)
c.Assert(maxCols, Equals, 1)
}
func (l *LibSuite) TestReadRowsFromSheetWithEmptyCells(c *C) {
var sharedstringsXML = bytes.NewBufferString(`
Bob
Alice
Sue
Yes
No
`)
var sheetxml = bytes.NewBufferString(`
0
1
2
3
4
3
4
3
`)
worksheet := new(xlsxWorksheet)
err := xml.NewDecoder(sheetxml).Decode(worksheet)
c.Assert(err, IsNil)
sst := new(xlsxSST)
err = xml.NewDecoder(sharedstringsXML).Decode(sst)
c.Assert(err, IsNil)
file := new(File)
file.referenceTable = MakeSharedStringRefTable(sst)
rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
c.Assert(maxRows, Equals, 3)
c.Assert(maxCols, Equals, 3)
row := rows[2]
c.Assert(len(row.Cells), Equals, 3)
cell1 := row.Cells[0]
c.Assert(cell1.String(), Equals, "No")
cell2 := row.Cells[1]
c.Assert(cell2.String(), Equals,"")
cell3 := row.Cells[2]
c.Assert(cell3.String(), Equals, "Yes")
}
func (l *LibSuite) TestReadRowsFromSheetWithTrailingEmptyCells(c *C) {
var row *Row
var cell1, cell2, cell3, cell4 *Cell
var sharedstringsXML = bytes.NewBufferString(`
ABCD`)
var sheetxml = bytes.NewBufferString(`
0123
1
1
1
1
1
1
1
`)
worksheet := new(xlsxWorksheet)
err := xml.NewDecoder(sheetxml).Decode(worksheet)
c.Assert(err, IsNil)
sst := new(xlsxSST)
err = xml.NewDecoder(sharedstringsXML).Decode(sst)
c.Assert(err, IsNil)
file := new(File)
file.referenceTable = MakeSharedStringRefTable(sst)
rows, maxCol, maxRow := readRowsFromSheet(worksheet, file)
c.Assert(maxCol, Equals, 4)
c.Assert(maxRow, Equals, 8)
row = rows[0]
c.Assert(len(row.Cells), Equals, 4)
cell1 = row.Cells[0]
c.Assert(cell1.String(), Equals, "A")
cell2 = row.Cells[1]
c.Assert(cell2.String(), Equals, "B")
cell3 = row.Cells[2]
c.Assert(cell3.String(), Equals, "C")
cell4 = row.Cells[3]
c.Assert(cell4.String(), Equals, "D")
row = rows[1]
c.Assert(len(row.Cells), Equals, 4)
cell1 = row.Cells[0]
c.Assert(cell1.String(), Equals, "1")
cell2 = row.Cells[1]
c.Assert(cell2.String(), Equals, "")
cell3 = row.Cells[2]
c.Assert(cell3.String(), Equals, "")
cell4 = row.Cells[3]
c.Assert(cell4.String(), Equals, "")
}