Browse Source

Merge branch 'copy_of_original'

DamianSzkuat 6 years ago
parent
commit
fa962123c0
12 changed files with 950 additions and 644 deletions
  1. 1 0
      .gitignore
  2. 14 0
      row.go
  3. 0 2
      sheet.go
  4. 12 2
      stream_cell.go
  5. 100 34
      stream_file.go
  6. 126 45
      stream_file_builder.go
  7. 5 10
      stream_style.go
  8. 571 0
      stream_style_test.go
  9. 98 545
      stream_test.go
  10. 6 6
      style.go
  11. 15 0
      write.go
  12. 2 0
      xmlWorksheet.go

+ 1 - 0
.gitignore

@@ -4,3 +4,4 @@
 xlsx.test
 *.swp
 coverage.txt
+.idea

+ 14 - 0
row.go

@@ -25,3 +25,17 @@ func (r *Row) AddCell() *Cell {
 	r.Sheet.maybeAddCol(len(r.Cells))
 	return cell
 }
+
+// AddStreamCell takes as input a StreamCell, creates a new Cell from it,
+// and appends the new cell to the row.
+func (r *Row) AddStreamCell(streamCell StreamCell) {
+	cell := NewCell(r)
+	cell.Value = streamCell.cellData
+	cell.style = streamCell.cellStyle.style
+	cell.NumFmt = builtInNumFmt[streamCell.cellStyle.xNumFmtId]
+	cell.cellType = streamCell.cellType
+	r.Cells = append(r.Cells, cell)
+	r.Sheet.maybeAddCol(len(r.Cells))
+}
+
+

+ 0 - 2
sheet.go

@@ -136,7 +136,6 @@ func (s *Sheet) SetColWidth(startcol, endcol int, width float64) error {
 	for ; startcol < end; startcol++ {
 		s.Cols[startcol].Width = width
 	}
-
 	return nil
 }
 
@@ -259,7 +258,6 @@ func (s *Sheet) makeXLSXSheet(refTable *RefTable, styles *xlsxStyleSheet) *xlsxW
 		if col.Width == 0 {
 			col.Width = ColWidth
 			customWidth = false
-
 		} else {
 			customWidth = true
 		}

+ 12 - 2
stream_cell.go

@@ -1,6 +1,9 @@
 package xlsx
 
-import "strconv"
+import (
+	"strconv"
+	"time"
+)
 
 // StreamCell holds the data, style and type of cell for streaming
 type StreamCell struct {
@@ -34,8 +37,15 @@ func MakeIntegerStreamCell(cellData int) StreamCell {
 	return NewStreamCell(strconv.Itoa(cellData), Integers, CellTypeNumeric)
 }
 
-// MakeStyledIntegerStreamCell created a new cell that holds an integer value (represented as string)
+// MakeStyledIntegerStreamCell creates a new cell that holds an integer value (represented as string)
 // and is styled according to the given style.
 func MakeStyledIntegerStreamCell(cellData int, cellStyle StreamStyle) StreamCell {
 	return NewStreamCell(strconv.Itoa(cellData), cellStyle, CellTypeNumeric)
 }
+
+// MakeDateStreamCell creates a new cell that holds a date value and is formatted as dd-mm-yyyy and
+// and is of type numeric
+func MakeDateStreamCell(t time.Time) StreamCell {
+	excelTime := TimeToExcelTime(t, false)
+	return NewStreamCell(strconv.Itoa(int(excelTime)), Dates, CellTypeNumeric)
+}

+ 100 - 34
stream_file.go

@@ -15,8 +15,8 @@ type StreamFile struct {
 	zipWriter      *zip.Writer
 	currentSheet   *streamSheet
 	styleIds       [][]int
-	err            error
 	styleIdMap	   map[StreamStyle]int
+	err            error
 }
 
 type streamSheet struct {
@@ -32,19 +32,16 @@ type streamSheet struct {
 }
 
 var (
-	NoCurrentSheetError     = errors.New("no Current Sheet")
-	WrongNumberOfRowsError  = errors.New("invalid number of cells passed to Write. All calls to Write on the same sheet must have the same number of cells")
-	AlreadyOnLastSheetError = errors.New("NextSheet() called, but already on last sheet")
-	WrongNumberOfCellTypesError = errors.New("the numbers of cells and cell types do not match")
+	NoCurrentSheetError      = errors.New("no Current Sheet")
+	WrongNumberOfRowsError   = errors.New("invalid number of cells passed to Write. All calls to Write on the same sheet must have the same number of cells")
+	AlreadyOnLastSheetError  = errors.New("NextSheet() called, but already on last sheet")
 	UnsupportedCellTypeError = errors.New("the given cell type is not supported")
-	UnsupportedDataTypeError = errors.New("the given data type is not supported")
 )
 
 // Write will write a row of cells to the current sheet. Every call to Write on the same sheet must contain the
 // same number of cells as the header provided when the sheet was created or an error will be returned. This function
 // will always trigger a flush on success. Currently the only supported data type is string data.
-// TODO update comment
-func (sf *StreamFile) Write(cells []StreamCell) error {
+func (sf *StreamFile) Write(cells []string) error {
 	if sf.err != nil {
 		return sf.err
 	}
@@ -56,8 +53,23 @@ func (sf *StreamFile) Write(cells []StreamCell) error {
 	return sf.zipWriter.Flush()
 }
 
-//TODO Add comment
-func (sf *StreamFile) WriteAll(records [][]StreamCell) error {
+// WriteWithStyle will write a row of cells to the current sheet. Every call to WriteWithStyle on the same sheet must
+// contain the same number of cells as the header provided when the sheet was created or an error will be returned.
+// This function will always trigger a flush on success. WriteWithStyle supports all data types and styles that
+// are supported by StreamCell.
+func (sf *StreamFile) WriteWithStyle(cells []StreamCell) error {
+	if sf.err != nil {
+		return sf.err
+	}
+	err := sf.writeWithStyle(cells)
+	if err != nil {
+		sf.err = err
+		return err
+	}
+	return sf.zipWriter.Flush()
+}
+
+func (sf *StreamFile) WriteAll(records [][]string) error {
 	if sf.err != nil {
 		return sf.err
 	}
@@ -71,21 +83,79 @@ func (sf *StreamFile) WriteAll(records [][]StreamCell) error {
 	return sf.zipWriter.Flush()
 }
 
-// TODO Add comment
-func (sf *StreamFile) write(cells []StreamCell) error {
+// WriteAllWithStyle will write all the rows provided in records. All rows must have the same number of cells as
+// the headers. This function will always trigger a flush on success. WriteWithStyle supports all data types and
+// styles that are supported by StreamCell.
+func (sf *StreamFile) WriteAllWithStyle(records [][]StreamCell) error{
+	if sf.err != nil {
+		return sf.err
+	}
+	for _, row := range records {
+		err := sf.writeWithStyle(row)
+		if err != nil {
+			sf.err = err
+			return err
+		}
+	}
+	return sf.zipWriter.Flush()
+}
+
+func (sf *StreamFile) write(cells []string) error {
 	if sf.currentSheet == nil {
 		return NoCurrentSheetError
 	}
 	if len(cells) != sf.currentSheet.columnCount {
 		return WrongNumberOfRowsError
 	}
-	//if len(cells) != len(cellTypes) {
-	//	return WrongNumberOfCellTypesError
-	//}
-
 	sf.currentSheet.rowCount++
+	if err := sf.currentSheet.write(`<row r="` + strconv.Itoa(sf.currentSheet.rowCount) + `">`); err != nil {
+		return err
+	}
+	for colIndex, cellData := range cells {
+		// documentation for the c.t (cell.Type) attribute:
+		// b (Boolean): Cell containing a boolean.
+		// d (Date): Cell contains a date in the ISO 8601 format.
+		// e (Error): Cell containing an error.
+		// inlineStr (Inline String): Cell containing an (inline) rich string, i.e., one not in the shared string table.
+		// If this cell type is used, then the cell value is in the is element rather than the v element in the cell (c element).
+		// n (Number): Cell containing a number.
+		// s (Shared String): Cell containing a shared string.
+		// str (String): Cell containing a formula string.
+		cellCoordinate := GetCellIDStringFromCoords(colIndex, sf.currentSheet.rowCount-1)
+		cellType := "inlineStr"
+		cellOpen := `<c r="` + cellCoordinate + `" t="` + cellType + `"`
+		// Add in the style id if the cell isn't using the default style
+		if colIndex < len(sf.currentSheet.styleIds) && sf.currentSheet.styleIds[colIndex] != 0 {
+			cellOpen += ` s="` + strconv.Itoa(sf.currentSheet.styleIds[colIndex]) + `"`
+		}
+		cellOpen += `><is><t>`
+		cellClose := `</t></is></c>`
 
-	// This is the XML row opening
+		if err := sf.currentSheet.write(cellOpen); err != nil {
+			return err
+		}
+		if err := xml.EscapeText(sf.currentSheet.writer, []byte(cellData)); err != nil {
+			return err
+		}
+		if err := sf.currentSheet.write(cellClose); err != nil {
+			return err
+		}
+	}
+	if err := sf.currentSheet.write(`</row>`); err != nil {
+		return err
+	}
+	return sf.zipWriter.Flush()
+}
+
+func (sf *StreamFile) writeWithStyle(cells []StreamCell) error {
+	if sf.currentSheet == nil {
+		return NoCurrentSheetError
+	}
+	if len(cells) != sf.currentSheet.columnCount {
+		return WrongNumberOfRowsError
+	}
+	sf.currentSheet.rowCount++
+	// Write the row opening
 	if err := sf.currentSheet.write(`<row r="` + strconv.Itoa(sf.currentSheet.rowCount) + `">`); err != nil {
 		return err
 	}
@@ -96,24 +166,23 @@ func (sf *StreamFile) write(cells []StreamCell) error {
 		cellCoordinate := GetCellIDStringFromCoords(colIndex, sf.currentSheet.rowCount-1)
 
 		// Get the cell type string
-		cellType, err := GetCellTypeAsString(cell.cellType)
+		cellType, err := getCellTypeAsString(cell.cellType)
 		if err != nil {
-			return  err
+			return err
 		}
 
 		// Build the XML cell opening
 		cellOpen := `<c r="` + cellCoordinate + `" t="` + cellType + `"`
-		// Add in the style id if the cell isn't using the default style
+		// Add in the style id of the stream cell.
 		if idx, ok := sf.styleIdMap[cell.cellStyle]; ok {
 			cellOpen += ` s="` + strconv.Itoa(idx) + `"`
 		} else {
-			return errors.New("Trying to make use of a style that has not been added!")
+			return errors.New("trying to make use of a style that has not been added")
 		}
-
 		cellOpen += `>`
 
 		// The XML cell contents
-		cellContentsOpen, cellContentsClose, err := GetCellContentOpenAncCloseTags(cell.cellType)
+		cellContentsOpen, cellContentsClose, err := getCellContentOpenAncCloseTags(cell.cellType)
 		if err != nil {
 			return err
 		}
@@ -146,14 +215,14 @@ func (sf *StreamFile) write(cells []StreamCell) error {
 			return err
 		}
 	}
+	// Write the row ending
 	if err := sf.currentSheet.write(`</row>`); err != nil {
 		return err
 	}
 	return sf.zipWriter.Flush()
 }
 
-
-func GetCellTypeAsString(cellType CellType) (string, error) {
+func getCellTypeAsString(cellType CellType) (string, error) {
 	// documentation for the c.t (cell.Type) attribute:
 	// b (Boolean): Cell containing a boolean.
 	// d (Date): Cell contains a date in the ISO 8601 format.
@@ -175,8 +244,7 @@ func GetCellTypeAsString(cellType CellType) (string, error) {
 	case CellTypeNumeric:
 		return "n", nil
 	case CellTypeString:
-		// TODO Currently inline strings are typed as shared strings
-		// TODO remove once the tests have been changed
+		// TODO Currently shared strings are types as inline strings
 		return "inlineStr", nil
 		// return "s", nil
 	case CellTypeStringFormula:
@@ -186,13 +254,11 @@ func GetCellTypeAsString(cellType CellType) (string, error) {
 	}
 }
 
-func GetCellContentOpenAncCloseTags(cellType CellType) (string, string, error) {
-	// TODO Currently inline strings are types as shared strings
-	// TODO remove once the tests have been changed
-	if cellType == CellTypeString {
-		return `<is><t>`, `</t></is>`, nil
-	}
+func getCellContentOpenAncCloseTags(cellType CellType) (string, string, error) {
 	switch cellType{
+	case CellTypeString:
+		// TODO Currently shared strings are types as inline strings
+		return `<is><t>`, `</t></is>`, nil
 	case CellTypeInline:
 		return `<is><t>`, `</t></is>`, nil
 	case CellTypeStringFormula:
@@ -305,4 +371,4 @@ func (sf *StreamFile) writeSheetEnd() error {
 func (ss *streamSheet) write(data string) error {
 	_, err := ss.writer.Write([]byte(data))
 	return err
-}
+}

+ 126 - 45
stream_file_builder.go

@@ -33,14 +33,16 @@ import (
 )
 
 type StreamFileBuilder struct {
-	built              	bool
-	xlsxFile           	*File
-	zipWriter          	*zip.Writer
-	// cellTypeToStyleIds map[CellType]int
-	maxStyleId         	int
-	styleIds           	[][]int
-	styleIdMap		   	map[StreamStyle]int
-	streamStyles		[]StreamStyle
+	built              bool
+	firstSheetAdded    bool
+	customStylesAdded  bool
+	xlsxFile           *File
+	zipWriter          *zip.Writer
+	cellTypeToStyleIds map[CellType]int
+	maxStyleId         int
+	styleIds           [][]int
+	// streamStyles	   map[StreamStyle]struct{}
+	styleIdMap		   map[StreamStyle]int
 }
 
 const (
@@ -61,8 +63,9 @@ func NewStreamFileBuilder(writer io.Writer) *StreamFileBuilder {
 	return &StreamFileBuilder{
 		zipWriter:          zip.NewWriter(writer),
 		xlsxFile:           NewFile(),
-		// cellTypeToStyleIds: make(map[CellType]int),
+		cellTypeToStyleIds: make(map[CellType]int),
 		maxStyleId:         initMaxStyleId,
+		// streamStyles: 		make(map[StreamStyle]struct{}),
 		styleIdMap:			make(map[StreamStyle]int),
 	}
 }
@@ -80,14 +83,13 @@ func NewStreamFileBuilderForPath(path string) (*StreamFileBuilder, error) {
 // AddSheet will add sheets with the given name with the provided headers. The headers cannot be edited later, and all
 // rows written to the sheet must contain the same number of cells as the header. Sheet names must be unique, or an
 // error will be thrown.
-func (sb *StreamFileBuilder) AddSheet(name string, cells []StreamCell) error {
+func (sb *StreamFileBuilder) AddSheet(name string, headers []string, cellTypes []*CellType) error {
 	if sb.built {
 		return BuiltStreamFileBuilderError
 	}
-	//if len(cellTypes) > len(headers) {
-	//	return errors.New("cellTypes is longer than headers")
-	//}
-
+	if len(cellTypes) > len(headers) {
+		return errors.New("cellTypes is longer than headers")
+	}
 	sheet, err := sb.xlsxFile.AddSheet(name)
 	if err != nil {
 		// Set built on error so that all subsequent calls to the builder will also fail.
@@ -96,26 +98,70 @@ func (sb *StreamFileBuilder) AddSheet(name string, cells []StreamCell) error {
 	}
 	sb.styleIds = append(sb.styleIds, []int{})
 	row := sheet.AddRow()
+	if count := row.WriteSlice(&headers, -1); count != len(headers) {
+		// Set built on error so that all subsequent calls to the builder will also fail.
+		sb.built = true
+		return errors.New("failed to write headers")
+	}
+	for i, cellType := range cellTypes {
+		var cellStyleIndex int
+		var ok bool
+		if cellType != nil {
+			// The cell type is one of the attributes of a Style.
+			// Since it is the only attribute of Style that we use, we can assume that cell types
+			// map one to one with Styles and their Style ID.
+			// If a new cell type is used, a new style gets created with an increased id, if an existing cell type is
+			// used, the pre-existing style will also be used.
+			cellStyleIndex, ok = sb.cellTypeToStyleIds[*cellType]
+			if !ok {
+				sb.maxStyleId++
+				cellStyleIndex = sb.maxStyleId
+				sb.cellTypeToStyleIds[*cellType] = sb.maxStyleId
+			}
+			sheet.Cols[i].SetType(*cellType)
+		}
+		sb.styleIds[len(sb.styleIds)-1] = append(sb.styleIds[len(sb.styleIds)-1], cellStyleIndex)
+	}
+	return nil
+}
 
-	// TODO WriteSlice does not write the correct styles/types to the headers yet
-	headers := []string{}
-	for _, cell := range cells {
-		headers = append(headers, cell.cellData)
+// TODO update comments
+// AddSheetWithStyle will add sheets with the given name with the provided headers. The headers cannot be edited later, and all
+// rows written to the sheet must contain the same number of cells as the header. Sheet names must be unique, or an
+// error will be thrown. Additionally AddSheetWithStyle allows to add Style information to the headers.
+func (sb *StreamFileBuilder) AddSheetWithStyle(name string, cells []StreamCell) error {
+	if sb.built {
+		return BuiltStreamFileBuilderError
+	}
+	sheet, err := sb.xlsxFile.AddSheet(name)
+	if err != nil {
+		// Set built on error so that all subsequent calls to the builder will also fail.
+		sb.built = true
+		return err
 	}
+	// To make sure no new styles can be added after adding a sheet
+	sb.firstSheetAdded = true
 
-	if count := row.WriteSlice(&headers, -1); count != len(headers) {
+	// Check if all styles in the headers have been created
+	for _,cell := range cells{
+		if _, ok := sb.styleIdMap[cell.cellStyle]; !ok {
+			return errors.New("trying to make use of a style that has not been added")
+		}
+	}
+	// TODO Is needed for stream file to work but is not needed for streaming with styles
+	sb.styleIds = append(sb.styleIds, []int{})
+
+	// Set the values of the first row and the the number of columns
+	row := sheet.AddRow()
+	if count := row.WriteCellSlice(cells, -1); count != len(cells) {
 		// Set built on error so that all subsequent calls to the builder will also fail.
 		sb.built = true
 		return errors.New("failed to write headers")
 	}
 
+	// Set default column types based on the cel types in the first row
 	for i, cell := range cells {
-		if cellStyleIndex, ok := sb.styleIdMap[cell.cellStyle]; ok {
-			sheet.Cols[i].SetType(cell.cellType)
-			sb.styleIds[len(sb.styleIds)-1] = append(sb.styleIds[len(sb.styleIds)-1], cellStyleIndex)
-		} else {
-			return errors.New("trying to make use of a style that has not been added")
-		}
+		sheet.Cols[i].SetType(cell.cellType)
 	}
 	return nil
 }
@@ -128,13 +174,24 @@ func (sb *StreamFileBuilder) Build() (*StreamFile, error) {
 	}
 	sb.built = true
 
+	// Marshall Parts resets the style sheet, so to keep style information that has been added by the user
+	// we have to marshal it beforehand and add it again after the entire file has been marshaled
+	var xmlStylesSheetString string
+	var err error
+	if sb.customStylesAdded{
+		xmlStylesSheetString, err = sb.marshalStyles()
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	parts, err := sb.xlsxFile.MarshallParts()
 	if err != nil {
 		return nil, err
 	}
-	parts["xl/styles.xml"], err = sb.marshalStyles()
-	if err != nil {
-		return nil, err
+
+	if sb.customStylesAdded{
+		parts["xl/styles.xml"] = xmlStylesSheetString
 	}
 
 	es := &StreamFile{
@@ -143,7 +200,7 @@ func (sb *StreamFileBuilder) Build() (*StreamFile, error) {
 		sheetXmlPrefix: make([]string, len(sb.xlsxFile.Sheets)),
 		sheetXmlSuffix: make([]string, len(sb.xlsxFile.Sheets)),
 		styleIds:       sb.styleIds,
-		styleIdMap:		sb.styleIdMap,
+		styleIdMap:     sb.styleIdMap,
 	}
 	for path, data := range parts {
 		// If the part is a sheet, don't write it yet. We only want to write the XLSX metadata files, since at this
@@ -171,30 +228,55 @@ func (sb *StreamFileBuilder) Build() (*StreamFile, error) {
 }
 
 func (sb *StreamFileBuilder) marshalStyles() (string, error) {
-	for _,streamStyle := range sb.streamStyles{
-		XfId := handleStyleForXLSX(streamStyle.style, streamStyle.xNumFmtId, sb.xlsxFile.styles)
-		sb.styleIdMap[streamStyle] = XfId
-	}
-
 	styleSheetXMLString, err := sb.xlsxFile.styles.Marshal()
 	if err!=nil {
 		return "", err
 	}
-
 	return styleSheetXMLString, nil
 }
 
-// AddStreamStyle adds a StreamStyle to the list of styles that can be used in the file
-// This function will only work before the file is built and will throw an error
-// if it is called after building the file.
+// AddStreamStyle adds a new style to the style sheet.
+// Only Styles that have been added through this function will be usable.
+// This function cannot be used after AddSheetWithStyle has been called, and if it is
+// called after AddSheetWithStyle it will return an error.
+//func (sb *StreamFileBuilder) AddStreamStyle(streamStyle StreamStyle) error {
+//	if sb.firstSheetAdded {
+//		return errors.New("at least one sheet has been added, cannot add new styles anymore")
+//	}
+//	sb.streamStyles[streamStyle] = struct{}{}
+//	return nil
+//}
+
+// AddStreamStyle adds a new style to the style sheet.
+// Only Styles that have been added through either this function or AddStreamStyleList will be usable.
+// This function cannot be used after AddSheetWithStyle has been called, and if it is
+// called after AddSheetWithStyle it will return an error.
 func (sb *StreamFileBuilder) AddStreamStyle(streamStyle StreamStyle) error {
-	if sb.built {
-		return errors.New("The style file has been built, cannot add new styles anymore.")
+	if sb.firstSheetAdded {
+		return errors.New("the style file has been built, cannot add new styles anymore")
+	}
+	if sb.xlsxFile.styles == nil {
+		sb.xlsxFile.styles = newXlsxStyleSheet(sb.xlsxFile.theme)
 	}
-	sb.streamStyles = append(sb.streamStyles, streamStyle)
+	XfId := handleStyleForXLSX(streamStyle.style, streamStyle.xNumFmtId, sb.xlsxFile.styles)
+	sb.styleIdMap[streamStyle] = XfId
+	sb.customStylesAdded = true
 	return nil
 }
 
+// AddStreamStyleList adds a list of new styles to the style sheet.
+// Only Styles that have been added through either this function or AddStreamStyle will be usable.
+// This function cannot be used after AddSheetWithStyle has been called, and if it is
+// called after AddSheetWithStyle it will return an error.
+func (sb *StreamFileBuilder) AddStreamStyleList(streamStyles []StreamStyle) error {
+	for _, streamStyle := range streamStyles {
+		err := sb.AddStreamStyle(streamStyle)
+		if err != nil{
+			return err
+		}
+	}
+	return nil
+}
 
 // processEmptySheetXML will take in the path and XML data of an empty sheet, and will save the beginning and end of the
 // XML file so that these can be written at the right time.
@@ -230,11 +312,11 @@ func getSheetIndex(sf *StreamFile, path string) (int, error) {
 	indexString := path[len(sheetFilePathPrefix) : len(path)-len(sheetFilePathSuffix)]
 	sheetXLSXIndex, err := strconv.Atoi(indexString)
 	if err != nil {
-		return -1, errors.New("Unexpected sheet file name from xlsx package")
+		return -1, errors.New("unexpected sheet file name from xlsx package")
 	}
 	if sheetXLSXIndex < 1 || len(sf.sheetXmlPrefix) < sheetXLSXIndex ||
 		len(sf.sheetXmlSuffix) < sheetXLSXIndex || len(sf.xlsxFile.Sheets) < sheetXLSXIndex {
-		return -1, errors.New("Unexpected sheet index")
+		return -1, errors.New("unexpected sheet index")
 	}
 	sheetArrayIndex := sheetXLSXIndex - 1
 	return sheetArrayIndex, nil
@@ -276,5 +358,4 @@ func splitSheetIntoPrefixAndSuffix(data string) (string, string, error) {
 		return "", "", errors.New("unexpected Sheet XML: SheetData close tag not found")
 	}
 	return sheetParts[0], sheetParts[1], nil
-}
-
+}

+ 5 - 10
stream_style.go

@@ -25,8 +25,9 @@ var BoldIntegers StreamStyle
 var ItalicIntegers StreamStyle
 var UnderlinedIntegers StreamStyle
 
-// var DefaultStyles []StreamStyle
+var Dates StreamStyle
 
+var Decimals StreamStyle
 
 var Bold *Font
 var Italic *Font
@@ -58,21 +59,15 @@ func init(){
 	ItalicStrings = MakeStringStyle(Italic, DefaultFill(), DefaultAlignment(), DefaultBorder())
 	UnderlinedStrings = MakeStringStyle(Underlined, DefaultFill(), DefaultAlignment(), DefaultBorder())
 
-	//DefaultStyles = append(DefaultStyles, Strings)
-	//DefaultStyles = append(DefaultStyles, BoldStrings)
-	//DefaultStyles = append(DefaultStyles, ItalicStrings)
-	//DefaultStyles = append(DefaultStyles, UnderlinedStrings)
-
 	// Init default Integer styles
 	Integers = MakeIntegerStyle(DefaultFont(), DefaultFill(), DefaultAlignment(), DefaultBorder())
 	BoldIntegers = MakeIntegerStyle(Bold, DefaultFill(), DefaultAlignment(), DefaultBorder())
 	ItalicIntegers = MakeIntegerStyle(Italic, DefaultFill(), DefaultAlignment(), DefaultBorder())
 	UnderlinedIntegers = MakeIntegerStyle(Underlined, DefaultFill(), DefaultAlignment(), DefaultBorder())
 
-	//DefaultStyles = append(DefaultStyles, Integers)
-	//DefaultStyles = append(DefaultStyles, BoldIntegers)
-	//DefaultStyles = append(DefaultStyles, ItalicIntegers)
-	//DefaultStyles = append(DefaultStyles, UnderlinedIntegers)
+	Dates = MakeDateStyle(DefaultFont(), DefaultFill(), DefaultAlignment(), DefaultBorder())
+
+	Decimals = MakeDecimalStyle(DefaultFont(), DefaultFill(), DefaultAlignment(), DefaultBorder())
 }
 
 // MakeStyle creates a new StreamStyle and add it to the styles that will be streamed

+ 571 - 0
stream_style_test.go

@@ -0,0 +1,571 @@
+package xlsx
+
+import (
+	"bytes"
+	"fmt"
+	. "gopkg.in/check.v1"
+	"io"
+	"reflect"
+	"time"
+)
+
+const (
+	StyleStreamTestsShouldMakeRealFiles = false
+)
+
+type StreamStyleSuite struct{}
+
+var _ = Suite(&StreamStyleSuite{})
+
+func (s *StreamSuite) TestStreamTestsShouldMakeRealFilesShouldBeFalse(t *C) {
+	if StyleStreamTestsShouldMakeRealFiles {
+		t.Fatal("TestsShouldMakeRealFiles should only be true for local debugging. Don't forget to switch back before commiting.")
+	}
+}
+
+func (s *StreamSuite) TestXlsxStreamWriteWithStyle(t *C) {
+	// When shouldMakeRealFiles is set to true this test will make actual XLSX files in the file system.
+	// This is useful to ensure files open in Excel, Numbers, Google Docs, etc.
+	// In case of issues you can use "Open XML SDK 2.5" to diagnose issues in generated XLSX files:
+	// https://www.microsoft.com/en-us/download/details.aspx?id=30425
+	testCases := []struct {
+		testName      string
+		sheetNames    []string
+		workbookData  [][][]StreamCell
+		expectedError error
+	}{
+		{
+			testName: "Style Test",
+			sheetNames: []string{
+				"Sheet1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("1"), MakeStringStreamCell("25"),
+						MakeStyledStringStreamCell("A", BoldStrings), MakeStringStreamCell("B")},
+					{MakeIntegerStreamCell(1234), MakeStyledIntegerStreamCell(98, BoldIntegers),
+						MakeStyledIntegerStreamCell(34, ItalicIntegers), MakeStyledIntegerStreamCell(26, UnderlinedIntegers)},
+				},
+			},
+		},
+		{
+			testName: "One Sheet",
+			sheetNames: []string{
+				"Sheet1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+				},
+			},
+		},
+		{
+			testName: "One Column",
+			sheetNames: []string{
+				"Sheet1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token")},
+					{MakeIntegerStreamCell(123)},
+				},
+			},
+		},
+		{
+			testName: "Several Sheets, with different numbers of columns and rows",
+			sheetNames: []string{
+				"Sheet 1", "Sheet 2", "Sheet3",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+				},
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
+						MakeStringStreamCell("Stock")},
+
+					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
+						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
+						MakeIntegerStreamCell(1)},
+
+					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
+						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
+						MakeIntegerStreamCell(3)},
+				},
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price")},
+
+					{MakeIntegerStreamCell(9853), MakeStringStreamCell("Guacamole"),
+						MakeIntegerStreamCell(500)},
+
+					{MakeIntegerStreamCell(2357), MakeStringStreamCell("Margarita"),
+						MakeIntegerStreamCell(700)},
+				},
+			},
+		},
+		{
+			testName: "Two Sheets with same the name",
+			sheetNames: []string{
+				"Sheet 1", "Sheet 1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+				},
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
+						MakeStringStreamCell("Stock")},
+
+					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
+						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
+						MakeIntegerStreamCell(1)},
+
+					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
+						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
+						MakeIntegerStreamCell(3)},
+				},
+			},
+			expectedError: fmt.Errorf("duplicate sheet name '%s'.", "Sheet 1"),
+		},
+		{
+			testName: "One Sheet Registered, tries to write to two",
+			sheetNames: []string{
+				"Sheet 1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+				},
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
+						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
+				},
+			},
+			expectedError: AlreadyOnLastSheetError,
+		},
+		{
+			testName: "One Sheet, too many columns in row 1",
+			sheetNames: []string{
+				"Sheet 1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
+						MakeStringStreamCell("asdf")},
+				},
+			},
+			expectedError: WrongNumberOfRowsError,
+		},
+		{
+			testName: "One Sheet, too few columns in row 1",
+			sheetNames: []string{
+				"Sheet 1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300)},
+				},
+			},
+			expectedError: WrongNumberOfRowsError,
+		},
+		{
+			testName: "Lots of Sheets, only writes rows to one, only writes headers to one, should not error and should still create a valid file",
+			sheetNames: []string{
+				"Sheet 1", "Sheet 2", "Sheet 3", "Sheet 4", "Sheet 5", "Sheet 6",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+				},
+				{{}},
+				{{MakeStringStreamCell("Id"), MakeStringStreamCell("Unit Cost")}},
+				{{}},
+				{{}},
+				{{}},
+			},
+		},
+		{
+			testName: "Two Sheets, only writes to one, should not error and should still create a valid file",
+			sheetNames: []string{
+				"Sheet 1", "Sheet 2",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
+						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
+
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+				},
+				{{}},
+			},
+		},
+		{
+			testName: "UTF-8 Characters. This XLSX File loads correctly with Excel, Numbers, and Google Docs. It also passes Microsoft's Office File Format Validator.",
+			sheetNames: []string{
+				"Sheet1",
+			},
+			workbookData: [][][]StreamCell{
+				{
+					// String courtesy of https://github.com/minimaxir/big-list-of-naughty-strings/
+					// Header row contains the tags that I am filtering on
+					{MakeStringStreamCell("Token"), MakeStringStreamCell(endSheetDataTag),
+						MakeStringStreamCell("Price"), MakeStringStreamCell(fmt.Sprintf(dimensionTag, "A1:D1"))},
+					// Japanese and emojis
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("パーティーへ行かないか"),
+						MakeIntegerStreamCell(300), MakeStringStreamCell("🍕🐵 🙈 🙉 🙊")},
+					// XML encoder/parser test strings
+					{MakeIntegerStreamCell(123), MakeStringStreamCell(`<?xml version="1.0" encoding="ISO-8859-1"?>`),
+						MakeIntegerStreamCell(300), MakeStringStreamCell(`<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>`)},
+					// Upside down text and Right to Left Arabic text
+					{MakeIntegerStreamCell(123), MakeStringStreamCell(`˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥
+					00˙Ɩ$-`), MakeIntegerStreamCell(300), MakeStringStreamCell(`ﷺ`)} ,
+					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
+						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+				},
+			},
+		},
+	}
+
+	for i, testCase := range testCases {
+		var filePath string
+		var buffer bytes.Buffer
+		if StyleStreamTestsShouldMakeRealFiles {
+			filePath = fmt.Sprintf("WorkbookWithStyle%d.xlsx", i)
+		}
+
+		err := writeStreamFileWithStyle(filePath, &buffer, testCase.sheetNames, testCase.workbookData, StyleStreamTestsShouldMakeRealFiles, []StreamStyle{})
+		if err != testCase.expectedError && err.Error() != testCase.expectedError.Error() {
+			t.Fatalf("Error differs from expected error. Error: %v, Expected Error: %v ", err, testCase.expectedError)
+		}
+		if testCase.expectedError != nil {
+			return
+		}
+		// read the file back with the xlsx package
+		var bufReader *bytes.Reader
+		var size int64
+		if !StyleStreamTestsShouldMakeRealFiles {
+			bufReader = bytes.NewReader(buffer.Bytes())
+			size = bufReader.Size()
+		}
+		actualSheetNames, actualWorkbookData := readXLSXFile(t, filePath, bufReader, size, StyleStreamTestsShouldMakeRealFiles)
+		// check if data was able to be read correctly
+		if !reflect.DeepEqual(actualSheetNames, testCase.sheetNames) {
+			t.Fatal("Expected sheet names to be equal")
+		}
+
+		expectedWorkbookDataStrings := [][][]string{}
+		for j,_ := range testCase.workbookData {
+			expectedWorkbookDataStrings = append(expectedWorkbookDataStrings, [][]string{})
+			for k,_ := range testCase.workbookData[j]{
+				expectedWorkbookDataStrings[j] = append(expectedWorkbookDataStrings[j], []string{})
+				for _, cell := range testCase.workbookData[j][k] {
+					expectedWorkbookDataStrings[j][k] = append(expectedWorkbookDataStrings[j][k], cell.cellData)
+				}
+			}
+
+		}
+		if !reflect.DeepEqual(actualWorkbookData, expectedWorkbookDataStrings) {
+			t.Fatal("Expected workbook data to be equal")
+		}
+	}
+}
+
+// writeStreamFile will write the file using this stream package
+func writeStreamFileWithStyle(filePath string, fileBuffer io.Writer, sheetNames []string, workbookData [][][]StreamCell,
+								shouldMakeRealFiles bool, customStyles []StreamStyle) error {
+	var file *StreamFileBuilder
+	var err error
+	if shouldMakeRealFiles {
+		file, err = NewStreamFileBuilderForPath(filePath)
+		if err != nil {
+			return err
+		}
+	} else {
+		file = NewStreamFileBuilder(fileBuffer)
+	}
+
+	defaultStyles := []StreamStyle{Strings,BoldStrings,ItalicIntegers,UnderlinedStrings,
+						Integers, BoldIntegers, ItalicIntegers, UnderlinedIntegers,
+						Dates}
+	allStylesToBeAdded := append(defaultStyles, customStyles...)
+	err = file.AddStreamStyleList(allStylesToBeAdded)
+	if err != nil {
+		return err
+	}
+
+	for i, sheetName := range sheetNames {
+		header := workbookData[i][0]
+		err := file.AddSheetWithStyle(sheetName, header)
+		if err != nil {
+			return err
+		}
+	}
+	streamFile, err := file.Build()
+	if err != nil {
+		return err
+	}
+	for i, sheetData := range workbookData {
+
+		if i != 0 {
+			err = streamFile.NextSheet()
+			if err != nil {
+				return err
+			}
+		}
+		for i, row := range sheetData {
+			if i == 0 {
+				continue
+			}
+			err = streamFile.WriteWithStyle(row)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	err = streamFile.Close()
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *StreamSuite) TestDates(t *C) {
+	var filePath string
+	var buffer bytes.Buffer
+	if StyleStreamTestsShouldMakeRealFiles {
+		filePath = fmt.Sprintf("Workbook_Date_test.xlsx")
+	}
+
+	sheetNames := []string{"Sheet1"}
+	workbookData := [][][]StreamCell{
+		{
+			{MakeStringStreamCell("Date:")},
+			{MakeDateStreamCell(time.Now())},
+		},
+	}
+
+	err := writeStreamFileWithStyle(filePath, &buffer, sheetNames, workbookData, StyleStreamTestsShouldMakeRealFiles, []StreamStyle{})
+	if err != nil {
+		t.Fatal("Error during writing")
+	}
+}
+
+func (s *StreamSuite) TestMakeNewStylesAndUseIt(t *C) {
+	var filePath string
+	var buffer bytes.Buffer
+	if StyleStreamTestsShouldMakeRealFiles {
+		filePath = fmt.Sprintf("Workbook_newStyle.xlsx")
+	}
+
+	timesNewRoman12 := NewFont(12, TimesNewRoman)
+	timesNewRoman12.Color = RGB_Dard_Green
+	courier20 := NewFont(12, Courier)
+	courier20.Color = RGB_Dark_Red
+
+	greenFill := NewFill(Solid_Cell_Fill, RGB_Light_Green, RGB_White)
+	redFill := NewFill(Solid_Cell_Fill, RGB_Light_Red, RGB_White)
+
+	greenStyle := MakeStyle(0, timesNewRoman12, greenFill, DefaultAlignment(), DefaultBorder())
+	redStyle := MakeStyle(0, courier20, redFill, DefaultAlignment(), DefaultBorder())
+
+	sheetNames := []string{"Sheet1"}
+	workbookData := [][][]StreamCell{
+		{
+			{MakeStringStreamCell("Header1"), MakeStringStreamCell("Header2")},
+			{MakeStyledStringStreamCell("Good", greenStyle), MakeStyledStringStreamCell("Bad", redStyle)},
+		},
+	}
+
+	err := writeStreamFileWithStyle(filePath, &buffer, sheetNames, workbookData, TestsShouldMakeRealFiles, []StreamStyle{greenStyle, redStyle})
+
+	if err != nil {
+		t.Fatal("Error during writing")
+	}
+
+	// read the file back with the xlsx package
+	var bufReader *bytes.Reader
+	var size int64
+	if !TestsShouldMakeRealFiles {
+		bufReader = bytes.NewReader(buffer.Bytes())
+		size = bufReader.Size()
+	}
+	actualSheetNames, actualWorkbookData := readXLSXFile(t, filePath, bufReader, size, TestsShouldMakeRealFiles)
+	// check if data was able to be read correctly
+	if !reflect.DeepEqual(actualSheetNames, sheetNames) {
+		t.Fatal("Expected sheet names to be equal")
+	}
+
+	expectedWorkbookDataStrings := [][][]string{}
+	for j, _ := range workbookData {
+		expectedWorkbookDataStrings = append(expectedWorkbookDataStrings, [][]string{})
+		for k, _ := range workbookData[j] {
+			expectedWorkbookDataStrings[j] = append(expectedWorkbookDataStrings[j], []string{})
+			for _, cell := range workbookData[j][k] {
+				expectedWorkbookDataStrings[j][k] = append(expectedWorkbookDataStrings[j][k], cell.cellData)
+			}
+		}
+
+	}
+	if !reflect.DeepEqual(actualWorkbookData, expectedWorkbookDataStrings) {
+		t.Fatal("Expected workbook data to be equal")
+	}
+}
+
+func (s *StreamSuite) TestCloseWithNothingWrittenToSheetsWithStyle(t *C) {
+	buffer := bytes.NewBuffer(nil)
+	file := NewStreamFileBuilder(buffer)
+
+	sheetNames := []string{"Sheet1", "Sheet2"}
+	workbookData := [][][]StreamCell{
+		{{MakeStringStreamCell("Header1"), MakeStringStreamCell("Header2")}},
+		{{MakeStringStreamCell("Header3"), MakeStringStreamCell("Header4")}},
+	}
+
+	defaultStyles := []StreamStyle{Strings,BoldStrings,ItalicIntegers,UnderlinedStrings,
+		Integers, BoldIntegers, ItalicIntegers, UnderlinedIntegers,
+		Dates}
+	err := file.AddStreamStyleList(defaultStyles)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = file.AddSheetWithStyle(sheetNames[0], workbookData[0][0])
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = file.AddSheetWithStyle(sheetNames[1], workbookData[1][0])
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	stream, err := file.Build()
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = stream.Close()
+	if err != nil {
+		t.Fatal(err)
+	}
+	bufReader := bytes.NewReader(buffer.Bytes())
+	size := bufReader.Size()
+
+	actualSheetNames, actualWorkbookData := readXLSXFile(t, "", bufReader, size, false)
+	// check if data was able to be read correctly
+	if !reflect.DeepEqual(actualSheetNames, sheetNames) {
+		t.Fatal("Expected sheet names to be equal")
+	}
+	expectedWorkbookDataStrings := [][][]string{}
+	for j,_ := range workbookData {
+		expectedWorkbookDataStrings = append(expectedWorkbookDataStrings, [][]string{})
+		for k,_ := range workbookData[j]{
+			expectedWorkbookDataStrings[j] = append(expectedWorkbookDataStrings[j], []string{})
+			for _, cell := range workbookData[j][k] {
+				expectedWorkbookDataStrings[j][k] = append(expectedWorkbookDataStrings[j][k], cell.cellData)
+			}
+		}
+
+	}
+	if !reflect.DeepEqual(actualWorkbookData, expectedWorkbookDataStrings) {
+		t.Fatal("Expected workbook data to be equal")
+	}
+}
+
+func (s *StreamSuite) TestBuildErrorsAfterBuildWithStyle(t *C) {
+	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
+
+	defaultStyles := []StreamStyle{Strings,BoldStrings,ItalicIntegers,UnderlinedStrings,
+		Integers, BoldIntegers, ItalicIntegers, UnderlinedIntegers,
+		Dates}
+	err := file.AddStreamStyleList(defaultStyles)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = file.AddSheetWithStyle("Sheet1", []StreamCell{MakeStringStreamCell("Header")})
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = file.AddSheetWithStyle("Sheet2", []StreamCell{MakeStringStreamCell("Header")})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = file.Build()
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = file.Build()
+	if err != BuiltStreamFileBuilderError {
+		t.Fatal(err)
+	}
+}
+
+func (s *StreamSuite) TestAddSheetWithStyleErrorsAfterBuild(t *C) {
+	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
+
+	defaultStyles := []StreamStyle{Strings,BoldStrings,ItalicIntegers,UnderlinedStrings,
+		Integers, BoldIntegers, ItalicIntegers, UnderlinedIntegers,
+		Dates}
+	err := file.AddStreamStyleList(defaultStyles)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = file.AddSheetWithStyle("Sheet1", []StreamCell{MakeStringStreamCell("Header")})
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = file.AddSheetWithStyle("Sheet2", []StreamCell{MakeStringStreamCell("Header2")})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = file.Build()
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = file.AddSheetWithStyle("Sheet3", []StreamCell{MakeStringStreamCell("Header3")})
+	if err != BuiltStreamFileBuilderError {
+		t.Fatal(err)
+	}
+}
+
+
+
+
+
+

+ 98 - 545
stream_test.go

@@ -11,7 +11,7 @@ import (
 )
 
 const (
-	TestsShouldMakeRealFiles = true
+	TestsShouldMakeRealFiles = false
 )
 
 type StreamSuite struct{}
@@ -32,46 +32,34 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 	testCases := []struct {
 		testName      string
 		sheetNames    []string
-		workbookData  [][][]StreamCell
+		workbookData  [][][]string
+		headerTypes   [][]*CellType
 		expectedError error
 	}{
-		{
-			testName: "Number Row",
-			sheetNames: []string{
-				"Sheet1",
-			},
-			workbookData: [][][]StreamCell{
-				{
-					{MakeStringStreamCell("1"), MakeStringStreamCell("25"),
-						MakeStringStreamCell("A"), MakeStringStreamCell("B")},
-					{MakeIntegerStreamCell(1234), MakeStyledIntegerStreamCell(98, BoldIntegers),
-						MakeStyledIntegerStreamCell(34, ItalicIntegers), MakeStyledIntegerStreamCell(26, UnderlinedIntegers)},
-				},
-			},
-		},
 		{
 			testName: "One Sheet",
 			sheetNames: []string{
 				"Sheet1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123"},
 				},
 			},
+			headerTypes: [][]*CellType{
+				{nil, CellTypeString.Ptr(), nil, CellTypeString.Ptr()},
+			},
 		},
 		{
 			testName: "One Column",
 			sheetNames: []string{
 				"Sheet1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token")},
-					{MakeIntegerStreamCell(123)},
+					{"Token"},
+					{"123"},
 				},
 			},
 		},
@@ -80,36 +68,20 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1", "Sheet 2", "Sheet3",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123"},
 				},
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
-						MakeStringStreamCell("Stock")},
-
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(1)},
-
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(3)},
+					{"Token", "Name", "Price", "SKU", "Stock"},
+					{"456", "Salsa", "200", "0346", "1"},
+					{"789", "Burritos", "400", "754", "3"},
 				},
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price")},
-
-					{MakeIntegerStreamCell(9853), MakeStringStreamCell("Guacamole"),
-						MakeIntegerStreamCell(500)},
-
-					{MakeIntegerStreamCell(2357), MakeStringStreamCell("Margarita"),
-						MakeIntegerStreamCell(700)},
+					{"Token", "Name", "Price"},
+					{"9853", "Guacamole", "500"},
+					{"2357", "Margarita", "700"},
 				},
 			},
 		},
@@ -118,26 +90,15 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1", "Sheet 1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123"},
 				},
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
-						MakeStringStreamCell("Stock")},
-
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(1)},
-
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(3)},
+					{"Token", "Name", "Price", "SKU", "Stock"},
+					{"456", "Salsa", "200", "0346", "1"},
+					{"789", "Burritos", "400", "754", "3"},
 				},
 			},
 			expectedError: fmt.Errorf("duplicate sheet name '%s'.", "Sheet 1"),
@@ -147,20 +108,14 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123"},
 				},
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
+					{"Token", "Name", "Price", "SKU"},
+					{"456", "Salsa", "200", "0346"},
 				},
 			},
 			expectedError: AlreadyOnLastSheetError,
@@ -170,14 +125,10 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeStringStreamCell("asdf")},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123", "asdf"},
 				},
 			},
 			expectedError: WrongNumberOfRowsError,
@@ -187,13 +138,10 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300)},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300"},
 				},
 			},
 			expectedError: WrongNumberOfRowsError,
@@ -203,16 +151,13 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1", "Sheet 2", "Sheet 3", "Sheet 4", "Sheet 5", "Sheet 6",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123"},
 				},
 				{{}},
-				{{MakeStringStreamCell("Id"), MakeStringStreamCell("Unit Cost")}},
+				{{"Id", "Unit Cost"}},
 				{{}},
 				{{}},
 				{{}},
@@ -223,13 +168,10 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1", "Sheet 2",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+					{"Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123"},
 				},
 				{{}},
 			},
@@ -239,308 +181,33 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet 1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
-					{MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
-						MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
-						MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
-						MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
-						MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU"),
-						MakeStringStreamCell("Token"), MakeStringStreamCell("Name"),
-						MakeStringStreamCell("Price"), MakeStringStreamCell("SKU")},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),
-						MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123),},
-					{MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346),
-						MakeIntegerStreamCell(456), MakeStringStreamCell("Salsa"),
-						MakeIntegerStreamCell(200), MakeIntegerStreamCell(346)},
-					{MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754),
-						MakeIntegerStreamCell(789), MakeStringStreamCell("Burritos"),
-						MakeIntegerStreamCell(400), MakeIntegerStreamCell(754)},
+					{"Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
+					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
+					{"456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346", "456", "Salsa", "200", "0346"},
+					{"789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754", "789", "Burritos", "400", "754"},
 				},
 			},
 		},
@@ -549,36 +216,30 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 				"Sheet1",
 			},
-			workbookData: [][][]StreamCell{
+			workbookData: [][][]string{
 				{
 					// String courtesy of https://github.com/minimaxir/big-list-of-naughty-strings/
 					// Header row contains the tags that I am filtering on
-					{MakeStringStreamCell("Token"), MakeStringStreamCell(endSheetDataTag),
-						MakeStringStreamCell("Price"), MakeStringStreamCell(fmt.Sprintf(dimensionTag, "A1:D1"))},
+					{"Token", endSheetDataTag, "Price", fmt.Sprintf(dimensionTag, "A1:D1")},
 					// Japanese and emojis
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("パーティーへ行かないか"),
-						MakeIntegerStreamCell(300), MakeStringStreamCell("🍕🐵 🙈 🙉 🙊")},
+					{"123", "パーティーへ行かないか", "300", "🍕🐵 🙈 🙉 🙊"},
 					// XML encoder/parser test strings
-					{MakeIntegerStreamCell(123), MakeStringStreamCell(`<?xml version="1.0" encoding="ISO-8859-1"?>`),
-						MakeIntegerStreamCell(300), MakeStringStreamCell(`<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>`)},
+					{"123", `<?xml version="1.0" encoding="ISO-8859-1"?>`, "300", `<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>`},
 					// Upside down text and Right to Left Arabic text
-					{MakeIntegerStreamCell(123), MakeStringStreamCell(`˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥
-					00˙Ɩ$-`), MakeIntegerStreamCell(300), MakeStringStreamCell(`ﷺ`)} ,
-					{MakeIntegerStreamCell(123), MakeStringStreamCell("Taco"),
-						MakeIntegerStreamCell(300), MakeIntegerStreamCell(123)},
+					{"123", `˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥
+					00˙Ɩ$-`, "300", `ﷺ`},
+					{"123", "Taco", "300", "0000000123"},
 				},
 			},
 		},
 	}
-
 	for i, testCase := range testCases {
 		var filePath string
 		var buffer bytes.Buffer
 		if TestsShouldMakeRealFiles {
 			filePath = fmt.Sprintf("Workbook%d.xlsx", i)
 		}
-
-		err := writeStreamFile(filePath, &buffer, testCase.sheetNames, testCase.workbookData, TestsShouldMakeRealFiles)
+		err := writeStreamFile(filePath, &buffer, testCase.sheetNames, testCase.workbookData, testCase.headerTypes, TestsShouldMakeRealFiles)
 		if err != testCase.expectedError && err.Error() != testCase.expectedError.Error() {
 			t.Fatalf("Error differs from expected error. Error: %v, Expected Error: %v ", err, testCase.expectedError)
 		}
@@ -597,19 +258,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 		if !reflect.DeepEqual(actualSheetNames, testCase.sheetNames) {
 			t.Fatal("Expected sheet names to be equal")
 		}
-
-		expectedWorkbookDataStrings := [][][]string{}
-		for j,_ := range testCase.workbookData {
-			expectedWorkbookDataStrings = append(expectedWorkbookDataStrings, [][]string{})
-			for k,_ := range testCase.workbookData[j]{
-				expectedWorkbookDataStrings[j] = append(expectedWorkbookDataStrings[j], []string{})
-				for _, cell := range testCase.workbookData[j][k] {
-					expectedWorkbookDataStrings[j][k] = append(expectedWorkbookDataStrings[j][k], cell.cellData)
-				}
-			}
-
-		}
-		if !reflect.DeepEqual(actualWorkbookData, expectedWorkbookDataStrings) {
+		if !reflect.DeepEqual(actualWorkbookData, testCase.workbookData) {
 			t.Fatal("Expected workbook data to be equal")
 		}
 	}
@@ -668,7 +317,7 @@ func (s *StreamSuite) TestXlsxStyleBehavior(t *C) {
 }
 
 // writeStreamFile will write the file using this stream package
-func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string, workbookData [][][]StreamCell, shouldMakeRealFiles bool) error {
+func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string, workbookData [][][]string, headerTypes [][]*CellType, shouldMakeRealFiles bool) error {
 	var file *StreamFileBuilder
 	var err error
 	if shouldMakeRealFiles {
@@ -679,22 +328,13 @@ func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string,
 	} else {
 		file = NewStreamFileBuilder(fileBuffer)
 	}
-
-	err = file.AddStreamStyle(Strings)
-	err = file.AddStreamStyle(BoldStrings)
-	err = file.AddStreamStyle(ItalicStrings)
-	err = file.AddStreamStyle(UnderlinedStrings)
-	err = file.AddStreamStyle(Integers)
-	err = file.AddStreamStyle(BoldIntegers)
-	err = file.AddStreamStyle(ItalicIntegers)
-	err = file.AddStreamStyle(UnderlinedIntegers)
-	if err != nil { // TODO handle all errors not just one
-		return err
-	}
-
 	for i, sheetName := range sheetNames {
 		header := workbookData[i][0]
-		err := file.AddSheet(sheetName, header)
+		var sheetHeaderTypes []*CellType
+		if i < len(headerTypes) {
+			sheetHeaderTypes = headerTypes[i]
+		}
+		err := file.AddSheet(sheetName, header, sheetHeaderTypes)
 		if err != nil {
 			return err
 		}
@@ -704,7 +344,6 @@ func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string,
 		return err
 	}
 	for i, sheetData := range workbookData {
-
 		if i != 0 {
 			err = streamFile.NextSheet()
 			if err != nil {
@@ -767,11 +406,11 @@ func readXLSXFile(t *C, filePath string, fileBuffer io.ReaderAt, size int64, sho
 func (s *StreamSuite) TestAddSheetErrorsAfterBuild(t *C) {
 	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
 
-	err := file.AddSheet("Sheet1", []StreamCell{MakeStringStreamCell("Header")})
+	err := file.AddSheet("Sheet1", []string{"Header"}, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = file.AddSheet("Sheet2", []StreamCell{MakeStringStreamCell("Header2")})
+	err = file.AddSheet("Sheet2", []string{"Header2"}, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -780,7 +419,7 @@ func (s *StreamSuite) TestAddSheetErrorsAfterBuild(t *C) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = file.AddSheet("Sheet3", []StreamCell{MakeStringStreamCell("Header3")})
+	err = file.AddSheet("Sheet3", []string{"Header3"}, nil)
 	if err != BuiltStreamFileBuilderError {
 		t.Fatal(err)
 	}
@@ -789,11 +428,11 @@ func (s *StreamSuite) TestAddSheetErrorsAfterBuild(t *C) {
 func (s *StreamSuite) TestBuildErrorsAfterBuild(t *C) {
 	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
 
-	err := file.AddSheet("Sheet1", []StreamCell{MakeStringStreamCell("Header")})
+	err := file.AddSheet("Sheet1", []string{"Header"}, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = file.AddSheet("Sheet2", []StreamCell{MakeStringStreamCell("Header")})
+	err = file.AddSheet("Sheet2", []string{"Header2"}, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -813,15 +452,15 @@ func (s *StreamSuite) TestCloseWithNothingWrittenToSheets(t *C) {
 	file := NewStreamFileBuilder(buffer)
 
 	sheetNames := []string{"Sheet1", "Sheet2"}
-	workbookData := [][][]StreamCell{
-		{{MakeStringStreamCell("Header1"), MakeStringStreamCell("Header2")}},
-		{{MakeStringStreamCell("Header3"), MakeStringStreamCell("Header4")}},
+	workbookData := [][][]string{
+		{{"Header1", "Header2"}},
+		{{"Header3", "Header4"}},
 	}
-	err := file.AddSheet(sheetNames[0], workbookData[0][0])
+	err := file.AddSheet(sheetNames[0], workbookData[0][0], nil)
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = file.AddSheet(sheetNames[1], workbookData[1][0])
+	err = file.AddSheet(sheetNames[1], workbookData[1][0], nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -842,93 +481,7 @@ func (s *StreamSuite) TestCloseWithNothingWrittenToSheets(t *C) {
 	if !reflect.DeepEqual(actualSheetNames, sheetNames) {
 		t.Fatal("Expected sheet names to be equal")
 	}
-	expectedWorkbookDataStrings := [][][]string{}
-	for j,_ := range workbookData {
-		expectedWorkbookDataStrings = append(expectedWorkbookDataStrings, [][]string{})
-		for k,_ := range workbookData[j]{
-			expectedWorkbookDataStrings[j] = append(expectedWorkbookDataStrings[j], []string{})
-			for _, cell := range workbookData[j][k] {
-				expectedWorkbookDataStrings[j][k] = append(expectedWorkbookDataStrings[j][k], cell.cellData)
-			}
-		}
-
-	}
-	if !reflect.DeepEqual(actualWorkbookData, expectedWorkbookDataStrings) {
-		t.Fatal("Expected workbook data to be equal")
-	}
-}
-
-func (s *StreamSuite) TestMakeNewStyleAndUseIt(t *C){
-	var filePath string
-	var buffer bytes.Buffer
-	if TestsShouldMakeRealFiles {
-		filePath = fmt.Sprintf("Workbook_newStyle.xlsx")
-	}
-
-	timesNewRoman12 := NewFont(12,TimesNewRoman)
-	timesNewRoman12.Color = RGB_Dard_Green
-	courier20:= NewFont(12, Courier)
-	courier20.Color = RGB_Dark_Red
-
-	greenFill := NewFill(Solid_Cell_Fill, RGB_Light_Green, RGB_White)
-	redFill   := NewFill(Solid_Cell_Fill, RGB_Light_Red,   RGB_White)
-
-	greenStyle := MakeStyle(0, timesNewRoman12, greenFill, DefaultAlignment(), DefaultBorder())
-	redStyle :=   MakeStyle(0, courier20, redFill, DefaultAlignment(), DefaultBorder())
-
-	sheetNames := []string{"Sheet1"}
-	workbookData := [][][]StreamCell{
-		{
-			{MakeStringStreamCell("Header1"), MakeStringStreamCell("Header2")},
-			{MakeStyledStringStreamCell("Good", greenStyle), MakeStyledStringStreamCell("Bad", redStyle)},
-		},
-	}
-
-	err := writeStreamFile(filePath, &buffer, sheetNames, workbookData, TestsShouldMakeRealFiles)
-
-	if err != nil {
-		t.Fatal("Error during writing")
-	}
-
-	// read the file back with the xlsx package
-	var bufReader *bytes.Reader
-	var size int64
-	if !TestsShouldMakeRealFiles {
-		bufReader = bytes.NewReader(buffer.Bytes())
-		size = bufReader.Size()
-	}
-	actualSheetNames, actualWorkbookData := readXLSXFile(t, filePath, bufReader, size, TestsShouldMakeRealFiles)
-	// check if data was able to be read correctly
-	if !reflect.DeepEqual(actualSheetNames, sheetNames) {
-		t.Fatal("Expected sheet names to be equal")
-	}
-
-	expectedWorkbookDataStrings := [][][]string{}
-	for j,_ := range workbookData {
-		expectedWorkbookDataStrings = append(expectedWorkbookDataStrings, [][]string{})
-		for k,_ := range workbookData[j]{
-			expectedWorkbookDataStrings[j] = append(expectedWorkbookDataStrings[j], []string{})
-			for _, cell := range workbookData[j][k] {
-				expectedWorkbookDataStrings[j][k] = append(expectedWorkbookDataStrings[j][k], cell.cellData)
-			}
-		}
-
-	}
-
-	if !reflect.DeepEqual(actualWorkbookData, expectedWorkbookDataStrings) {
+	if !reflect.DeepEqual(actualWorkbookData, workbookData) {
 		t.Fatal("Expected workbook data to be equal")
 	}
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
+}

+ 6 - 6
style.go

@@ -4,19 +4,19 @@ import "strconv"
 
 // Several popular font names that can be used to create fonts
 const (
-	Helvetica = "Helvetica"
-	Baskerville = "Baskerville Old Face"
+	Helvetica     = "Helvetica"
+	Baskerville   = "Baskerville Old Face"
 	TimesNewRoman = "Times New Roman"
-	Bodoni = "Bodoni MT"
-	GillSans = "Gill Sans MT"
-	Courier = "Courier"
+	Bodoni        = "Bodoni MT"
+	GillSans      = "Gill Sans MT"
+	Courier       = "Courier"
 )
 
 const (
 	RGB_Light_Green = "FFC6EFCE"
 	RGB_Dard_Green  = "FF006100"
 	RGB_Light_Red   = "FFFFC7CE"
-	RGB_Dark_Red     = "FF9C0006"
+	RGB_Dark_Red    = "FF9C0006"
 	RGB_White 		= "00000000"
 	RGB_Black 		= "FFFFFFFF"
 )

+ 15 - 0
write.go

@@ -63,6 +63,21 @@ func (r *Row) WriteSlice(e interface{}, cols int) int {
 	return i
 }
 
+// WriteCellSlice an array of Cell's to row r. Accepts an array of StreamCells
+// and writes the number of columns to write, 'cols'. If 'cols' is < 0,
+// the entire array will be written if possible. Returns the number of columns written.
+func (r *Row) WriteCellSlice(streamCells []StreamCell, cols int) int {
+	if cols == 0 {
+		return cols
+	}
+	i := 0
+	for _, streamCell := range streamCells {
+		r.AddStreamCell(streamCell)
+		i++
+	}
+	return i
+}
+
 // Writes a struct to row r. Accepts a pointer to struct type 'e',
 // and the number of columns to write, `cols`. If 'cols' is < 0,
 // the entire struct will be written if possible. Returns -1 if the 'e'

+ 2 - 0
xmlWorksheet.go

@@ -203,6 +203,8 @@ type xlsxCol struct {
 	Style        int     `xml:"style,attr"`
 	Width        float64 `xml:"width,attr"`
 	CustomWidth  bool    `xml:"customWidth,attr,omitempty"`
+	// TODO test
+	BestFit 	 bool    `xml:"bestFit,attr,omitempty"`
 	OutlineLevel uint8   `xml:"outlineLevel,attr,omitempty"`
 }