Skip to content

Commit

Permalink
Create directly on stream
Browse files Browse the repository at this point in the history
  • Loading branch information
bportelalp committed Nov 15, 2023
1 parent 0d267d8 commit 481b165
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 91 deletions.
9 changes: 7 additions & 2 deletions src/Beporsoft.TabularSheets/Builders/SpreadsheetBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,16 @@ public void Create(string path, params ITabularSheet[] tables)
ms.Seek(0, SeekOrigin.Begin);
ms.CopyTo(fs);
}

public MemoryStream Create(params ITabularSheet[] tables)
{
MemoryStream stream = new();
Create(stream, tables);
return stream;
}

public void Create(Stream stream, params ITabularSheet[] tables)
{
using var spreadsheet = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook);
WorkbookPart workbookPart = spreadsheet.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
Expand All @@ -66,8 +73,6 @@ public MemoryStream Create(params ITabularSheet[] tables)
AppendWorkbookStylePart(ref workbookPart);
AppendSharedStringTablePart(ref workbookPart);
workbookPart.Workbook.Save();
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
#endregion

Expand Down
2 changes: 2 additions & 0 deletions src/Beporsoft.TabularSheets/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

* NEW: New element `TabularBook` which allows to export multiple sheets inside a single spreadsheet.

* NEW: New method for create on existent stream.

## 1.2.2 - 2023-10-31

* FIX: `TabularSheet<T>.Options` is now `public`.
Expand Down
10 changes: 10 additions & 0 deletions src/Beporsoft.TabularSheets/TabularBook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ public void Create(string path)
builder.Create(path, Sheets.ToArray());
}

/// <summary>
/// Creates a spreadsheet document.
/// </summary>
/// <returns></returns>
public void Create(Stream stream)
{
SpreadsheetBuilder builder = new();
builder.Create(stream, Sheets.ToArray());
}

/// <summary>
/// Creates a spreadsheet document.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/Beporsoft.TabularSheets/TabularSheet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ public void Create(string path)
builder.Create(path, this);
}

/// <summary>
/// Creates a spreadsheet document on the given stream.
/// </summary>
/// <param name="stream"></param>
public void Create(Stream stream)
{
SpreadsheetBuilder builder = new();
builder.Create(stream, this);
}

/// <summary>
/// Creates a spreadsheet document
/// </summary>
Expand Down
110 changes: 109 additions & 1 deletion test/Beporsoft.TabularSheets.Test/TestSheetCreation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,114 @@ public void Create_CheckFileName()
});
}

[Test, Category("StreamCreation")]
public void CreateMemoryStream_Ok()
{
TabularSheet<Product> table = Product.GenerateProductSheet();

using (var ms = table.Create())
{
var sheetFixture = new SheetFixture(ms);
TabularSheetAsserter.AssertTabularSheet(table, sheetFixture);
}
}

[Test, Category("StreamCreation")]
public void CreateOnStream_WhichIsMemoryStream_Ok()
{
TabularSheet<Product> table = Product.GenerateProductSheet();

using (var ms = new MemoryStream())
{
table.Create(ms);
var sheetFixture = new SheetFixture(ms);
TabularSheetAsserter.AssertTabularSheet(table, sheetFixture);
}
}

[Test, Category("StreamCreation")]
public void CreateOnStream_WhichIsFileStream_OkIfReadWrite()
{
TabularSheet<Product> table = Product.GenerateProductSheet();
string path = _filesHandler.BuildPath($"Test{nameof(CreateOnStream_WhichIsFileStream_OkIfReadWrite)}.xlsx");

using (var fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite))
{
table.Create(fs);
}

var sheetFixture = new SheetFixture(path);
TabularSheetAsserter.AssertTabularSheet(table, sheetFixture);
}

[Test, Category("StreamCreation")]
public void CreateWorkbookMemoryStream_Ok()
{
TabularBook book = new TabularBook();

var tableProducts = Product.GenerateProductSheet(100);
var tableReviews = ProductReview.GenerateReviewSheet(tableProducts.Items, 10);

book.Add(tableProducts);
book.Add(tableReviews);

using MemoryStream ms = book.Create();
WorkbookFixture workbook = new(ms);

var productFixture = workbook.Sheets[nameof(Product)];
var reviewFixture = workbook.Sheets[nameof(ProductReview)];
TabularSheetAsserter.AssertTabularSheet(tableProducts, productFixture);
TabularSheetAsserter.AssertTabularSheet(tableReviews, reviewFixture);
}

[Test, Category("StreamCreation")]
public void CreateWorkbookOnStream_WhichIsMemoryStream_Ok()
{
TabularBook book = new TabularBook();

var tableProducts = Product.GenerateProductSheet(100);
var tableReviews = ProductReview.GenerateReviewSheet(tableProducts.Items, 10);
book.Add(tableProducts);
book.Add(tableReviews);

using (var ms = new MemoryStream())
{
book.Create(ms);
WorkbookFixture workbook = new(ms);

var productFixture = workbook.Sheets[nameof(Product)];
var reviewFixture = workbook.Sheets[nameof(ProductReview)];
TabularSheetAsserter.AssertTabularSheet(tableProducts, productFixture);
TabularSheetAsserter.AssertTabularSheet(tableReviews, reviewFixture);
}
}

[Test, Category("StreamCreation")]
public void CreateWorkbookOnStream_WhichIsFileStream_OkIfReadWrite()
{
string path = _filesHandler.BuildPath($"Test{nameof(CreateWorkbookOnStream_WhichIsFileStream_OkIfReadWrite)}.xlsx");

TabularBook book = new TabularBook();

var tableProducts = Product.GenerateProductSheet(100);
var tableReviews = ProductReview.GenerateReviewSheet(tableProducts.Items, 10);
book.Add(tableProducts);
book.Add(tableReviews);

using (var fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite))
{
book.Create(fs);
}

WorkbookFixture workbook = new(path);

var productFixture = workbook.Sheets[nameof(Product)];
var reviewFixture = workbook.Sheets[nameof(ProductReview)];
TabularSheetAsserter.AssertTabularSheet(tableProducts, productFixture);
TabularSheetAsserter.AssertTabularSheet(tableReviews, reviewFixture);
}


[OneTimeTearDown]
public void OneTimeTearDown()
{
Expand All @@ -60,7 +168,7 @@ public void OneTimeTearDown()
yield return new object?[] { "File.xlsx", "File.xlsx", new string[] { ".xlsx", ".xls" } };
yield return new object?[] { "File.xlsx", "File.xlsx", SpreadsheetFileExtension.AllowedExtensions };
yield return new object?[] { "File.xls", "File.xls", new string[] { ".xlsx", ".xls" } };
yield return new object?[] { "File.xlsx", "File", new string[] {".xlsx", ".xls" } };
yield return new object?[] { "File.xlsx", "File", new string[] { ".xlsx", ".xls" } };
yield return new object?[] { "File.xls", "File", new string[] { ".xls", ".xlsx" } };
yield return new object?[] { "File.csv", "File.csv", new string[] { ".xls", ".csv" } };
yield return new object?[] { "File.csv", "File.csv", CsvFileExtension.AllowedExtensions };
Expand Down
90 changes: 2 additions & 88 deletions test/Beporsoft.TabularSheets.Test/TestTabularSheet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public void Create_Data_AsExpected()
table.Create(path);
sheet = new SheetFixture(path);
}, Throws.Nothing);
AssertWorksheet(table, sheet);
TabularSheetAsserter.AssertTabularSheet(table, sheet);

// Generate as memory stream
Assert.That(() =>
Expand All @@ -67,7 +67,7 @@ public void Create_Data_AsExpected()
Console.WriteLine($"Created on: {_stopwatch.Elapsed.TotalMilliseconds:F3}ms");
sheet = new SheetFixture(ms);
}, Throws.Nothing);
AssertWorksheet(table, sheet);
TabularSheetAsserter.AssertTabularSheet(table, sheet);
}

[Test, Category("Stylesheet"), Category("Worksheet")]
Expand Down Expand Up @@ -431,91 +431,5 @@ public void OneTimeTearDown()

}

#region Assert Data
/// <summary>
/// Verify the data on every column is OK as expected
/// </summary>
/// <param name="table"></param>
/// <param name="column"></param>
/// <param name="sheet"></param>
private static void AssertWorksheet(TabularSheet<Product> table, SheetFixture sheet)
{
Assert.That(sheet.Title, Is.EqualTo(table.Title));
foreach (var col in table.Columns)
{
AssertColumnHeaderData(col, sheet);
AssertColumnBodyData(table, col, sheet);
}
AssertDimensions(table, sheet);
}

private static void AssertColumnHeaderData(TabularDataColumn<Product> column, SheetFixture sheet)
{
DocumentFormat.OpenXml.Spreadsheet.Cell headerCell = sheet.GetHeaderCellByColumn(column.Index);
Assert.Multiple(() =>
{
Assert.That(headerCell.InnerText, Is.Not.Null);
Assert.That(headerCell.DataType!.Value, Is.EqualTo(DocumentFormat.OpenXml.Spreadsheet.CellValues.SharedString));
var indexSharedString = Convert.ToInt32(headerCell.InnerText);
string? headerTitle = sheet.GetSharedString(indexSharedString);
Assert.That(headerTitle, Is.EqualTo(column.Title));
});
}

private static void AssertColumnBodyData(TabularSheet<Product> table, TabularDataColumn<Product> column, SheetFixture sheet)
{
List<DocumentFormat.OpenXml.Spreadsheet.Cell> bodyCells = sheet.GetBodyCellsByColumn(column.Index);
foreach (var cell in bodyCells)
{
Assert.Multiple(() =>
{
int row = CellRefBuilder.GetRowIndex(cell.CellReference!);
Product item = table[row - 1];
object value = column.Apply(item);
if (cell.DataType!.Value == DocumentFormat.OpenXml.Spreadsheet.CellValues.SharedString)
{
var indexSharedString = Convert.ToInt32(cell.InnerText);
string? content = sheet.GetSharedString(indexSharedString);
Assert.That(value.ToString(), Is.EqualTo(content));
}
else if (BuildHelpers.DateTimeTypes.Contains(value.GetType()))
{
var date = ((DateTime)value).ToOADate();
double content = Convert.ToDouble(cell.CellValue!.Text, CultureInfo.InvariantCulture);
Assert.That(cell.DataType!.Value, Is.EqualTo(DocumentFormat.OpenXml.Spreadsheet.CellValues.Number));
Assert.That(date, Is.EqualTo(content));
}
else if (BuildHelpers.TimeSpanTypes.Contains(value.GetType()))
{
var totalDays = ((TimeSpan)value).TotalDays;
double content = Convert.ToDouble(cell.CellValue!.Text, CultureInfo.InvariantCulture);
Assert.That(cell.DataType!.Value, Is.EqualTo(DocumentFormat.OpenXml.Spreadsheet.CellValues.Number));
Assert.That(totalDays, Is.EqualTo(content));
}
else if (cell.DataType!.Value == DocumentFormat.OpenXml.Spreadsheet.CellValues.Number)
{
// Treat all as double
double content = Convert.ToDouble(cell.CellValue!.Text, CultureInfo.InvariantCulture);
double valueDouble = Convert.ToDouble(value);
Assert.That(valueDouble, Is.EqualTo(content));
}
});
}
}

private static void AssertDimensions(TabularSheet<Product> table, SheetFixture sheet)
{
int rowCount = table.Count;
int colCount = table.ColumnCount;

string from = CellRefBuilder.BuildRef(0, 0);
string to = CellRefBuilder.BuildRef(rowCount, colCount, false); //Non zero based index because is count
string dimensions = CellRefBuilder.BuildRefRange(from, to);

Assert.That(sheet.GetDimensionReference(), Is.EqualTo(dimensions));
}
#endregion


}
}

0 comments on commit 481b165

Please sign in to comment.