From 481b16535467443636bdd59bca1bdf7d2200764c Mon Sep 17 00:00:00 2001 From: bportelalp Date: Wed, 15 Nov 2023 18:46:41 +0100 Subject: [PATCH] Create directly on stream --- .../Builders/SpreadsheetBuilder.cs | 9 +- src/Beporsoft.TabularSheets/CHANGELOG.md | 2 + src/Beporsoft.TabularSheets/TabularBook.cs | 10 ++ src/Beporsoft.TabularSheets/TabularSheet.cs | 10 ++ .../TestSheetCreation.cs | 110 +++++++++++++++++- .../TestTabularSheet.cs | 90 +------------- 6 files changed, 140 insertions(+), 91 deletions(-) diff --git a/src/Beporsoft.TabularSheets/Builders/SpreadsheetBuilder.cs b/src/Beporsoft.TabularSheets/Builders/SpreadsheetBuilder.cs index e5ca6c0..4be2b9a 100644 --- a/src/Beporsoft.TabularSheets/Builders/SpreadsheetBuilder.cs +++ b/src/Beporsoft.TabularSheets/Builders/SpreadsheetBuilder.cs @@ -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(); @@ -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 diff --git a/src/Beporsoft.TabularSheets/CHANGELOG.md b/src/Beporsoft.TabularSheets/CHANGELOG.md index 2b5aa00..eb6a92e 100644 --- a/src/Beporsoft.TabularSheets/CHANGELOG.md +++ b/src/Beporsoft.TabularSheets/CHANGELOG.md @@ -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.Options` is now `public`. diff --git a/src/Beporsoft.TabularSheets/TabularBook.cs b/src/Beporsoft.TabularSheets/TabularBook.cs index 6a66bf6..444d217 100644 --- a/src/Beporsoft.TabularSheets/TabularBook.cs +++ b/src/Beporsoft.TabularSheets/TabularBook.cs @@ -101,6 +101,16 @@ public void Create(string path) builder.Create(path, Sheets.ToArray()); } + /// + /// Creates a spreadsheet document. + /// + /// + public void Create(Stream stream) + { + SpreadsheetBuilder builder = new(); + builder.Create(stream, Sheets.ToArray()); + } + /// /// Creates a spreadsheet document. /// diff --git a/src/Beporsoft.TabularSheets/TabularSheet.cs b/src/Beporsoft.TabularSheets/TabularSheet.cs index c1503a3..00ae265 100644 --- a/src/Beporsoft.TabularSheets/TabularSheet.cs +++ b/src/Beporsoft.TabularSheets/TabularSheet.cs @@ -75,6 +75,16 @@ public void Create(string path) builder.Create(path, this); } + /// + /// Creates a spreadsheet document on the given stream. + /// + /// + public void Create(Stream stream) + { + SpreadsheetBuilder builder = new(); + builder.Create(stream, this); + } + /// /// Creates a spreadsheet document /// diff --git a/test/Beporsoft.TabularSheets.Test/TestSheetCreation.cs b/test/Beporsoft.TabularSheets.Test/TestSheetCreation.cs index e90fcdf..42b9bd2 100644 --- a/test/Beporsoft.TabularSheets.Test/TestSheetCreation.cs +++ b/test/Beporsoft.TabularSheets.Test/TestSheetCreation.cs @@ -47,6 +47,114 @@ public void Create_CheckFileName() }); } + [Test, Category("StreamCreation")] + public void CreateMemoryStream_Ok() + { + TabularSheet 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 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 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() { @@ -60,7 +168,7 @@ private static IEnumerable Data_FileHelpers_Verifypath 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 }; diff --git a/test/Beporsoft.TabularSheets.Test/TestTabularSheet.cs b/test/Beporsoft.TabularSheets.Test/TestTabularSheet.cs index daa5ee5..21a8a7b 100644 --- a/test/Beporsoft.TabularSheets.Test/TestTabularSheet.cs +++ b/test/Beporsoft.TabularSheets.Test/TestTabularSheet.cs @@ -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(() => @@ -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")] @@ -431,91 +431,5 @@ public void OneTimeTearDown() } - #region Assert Data - /// - /// Verify the data on every column is OK as expected - /// - /// - /// - /// - private static void AssertWorksheet(TabularSheet 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 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 table, TabularDataColumn column, SheetFixture sheet) - { - List 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 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 - - } } \ No newline at end of file