using ClosedXML.Attributes; using ClosedXML.Excel; using NUnit.Framework; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; namespace ClosedXML_Tests.Excel.Tables { [TestFixture] public class AppendingAndReplacingTableDataTests { public class TestObjectWithoutAttributes { public String Column1 { get; set; } public String Column2 { get; set; } } public class Person { public int Age { get; set; } [XLColumn(Header = "Last name", Order = 2)] public String LastName { get; set; } [XLColumn(Header = "First name", Order = 1)] public String FirstName { get; set; } [XLColumn(Header = "Full name", Order = 0)] public String FullName { get => string.Concat(FirstName, " ", LastName); } [XLColumn(Order = 3)] public DateTime DateOfBirth { get; set; } [XLColumn(Header = "Is active", Order = 4)] public bool IsActive; } private XLWorkbook PrepareWorkbook() { var wb = new XLWorkbook(); var ws = wb.AddWorksheet("Tables"); var data = new[] { new Person{FirstName = "Francois", LastName = "Botha", Age = 39, DateOfBirth = new DateTime(1980,1,1), IsActive = true}, new Person{FirstName = "Leon", LastName = "Oosthuizen", Age = 40, DateOfBirth = new DateTime(1979,1,1), IsActive = false}, new Person{FirstName = "Rian", LastName = "Prinsloo", Age = 41, DateOfBirth = new DateTime(1978,1,1), IsActive = false} }; ws.FirstCell().CellRight().CellBelow().InsertTable(data); ws.Columns().AdjustToContents(); return wb; } private XLWorkbook PrepareWorkbookWithAdditionalColumns() { var wb = PrepareWorkbook(); var ws = wb.Worksheets.First(); var table = ws.Tables.First(); table.HeadersRow() .LastCell().CellRight() .InsertData(new[] { "CumulativeAge", "NameLength", "IsOld", "HardCodedValue" }, transpose: true); table.Resize(ws.Range(table.FirstCell(), table.LastCell().CellRight(4))); table.Field("CumulativeAge").DataCells.ForEach(c => c.FormulaA1 = $"SUM($G$3:G{c.WorksheetRow().RowNumber()})"); table.Field("NameLength").DataCells.ForEach(c => c.FormulaA1 = $"LEN(B{c.WorksheetRow().RowNumber()})"); table.Field("IsOld").DataCells.ForEach(c => c.FormulaA1 = $"=G{c.WorksheetRow().RowNumber()}>=40"); table.Field("HardCodedValue").DataCells.Value = "40 is not old!"; return wb; } private Person[] NewData { get { return new[] { new Person{FirstName = "Michelle", LastName = "de Beer", Age = 35, DateOfBirth = new DateTime(1983,1,1), IsActive = false}, new Person{FirstName = "Marichen", LastName = "van der Gryp", Age = 30, DateOfBirth = new DateTime(1990,1,1), IsActive = true} }; } } [Test] public void AddingEmptyEnumerables() { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = null; Assert.AreEqual(null, table.AppendData(personEnumerable)); personEnumerable = new Person[] { }; Assert.AreEqual(null, table.AppendData(personEnumerable)); IEnumerable enumerable = null; Assert.AreEqual(null, table.AppendData(enumerable)); enumerable = new Person[] { }; Assert.AreEqual(null, table.AppendData(enumerable)); } } [Test] public void ReplaceWithEmptyEnumerables() { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = null; Assert.Throws(() => table.ReplaceData(personEnumerable)); personEnumerable = new Person[] { }; Assert.Throws(() => table.ReplaceData(personEnumerable)); IEnumerable enumerable = null; Assert.Throws(() => table.ReplaceData(enumerable)); enumerable = new Person[] { }; Assert.Throws(() => table.ReplaceData(enumerable)); } } [Test] public void CanAppendTypedEnumerable() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = NewData; var addedRange = table.AppendData(personEnumerable); Assert.AreEqual("B6:G7", addedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(5, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanAppendToTableWithTotalsRow() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); table.SetShowTotalsRow(true); table.Fields.Last().TotalsRowFunction = XLTotalsRowFunction.Average; IEnumerable personEnumerable = NewData; var addedRange = table.AppendData(personEnumerable); Assert.AreEqual("B6:G7", addedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(5, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanAppendTypedEnumerableAndPushDownCellsBelowTable() { using (var ms = new MemoryStream()) { var value = "Some value that will be overwritten"; IXLAddress address; using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); var cell = table.LastRow().FirstCell().CellRight(2).CellBelow(1); address = cell.Address; cell.Value = value; IEnumerable personEnumerable = NewData; var addedRange = table.AppendData(personEnumerable); Assert.AreEqual("B6:G7", addedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); var cell = ws.Cell(address); Assert.AreEqual("de Beer", cell.Value); Assert.AreEqual(5, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); Assert.AreEqual(value, cell.CellBelow(NewData.Count()).Value); } } } [Test] public void CanAppendUntypedEnumerable() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); var list = new ArrayList(); list.AddRange(NewData); var addedRange = table.AppendData(list); Assert.AreEqual("B6:G7", addedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(5, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanAppendDataTable() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = NewData; var ws2 = wb.AddWorksheet("temp"); var dataTable = ws2.FirstCell().InsertTable(personEnumerable).AsNativeDataTable(); var addedRange = table.AppendData(dataTable); Assert.AreEqual("B6:G7", addedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(5, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanReplaceWithTypedEnumerable() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = NewData; var replacedRange = table.ReplaceData(personEnumerable); Assert.AreEqual("B3:G4", replacedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(2, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanReplaceWithUntypedEnumerable() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); var list = new ArrayList(); list.AddRange(NewData); var replacedRange = table.ReplaceData(list); Assert.AreEqual("B3:G4", replacedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(2, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanReplaceWithDataTable() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = NewData; var ws2 = wb.AddWorksheet("temp"); var dataTable = ws2.FirstCell().InsertTable(personEnumerable).AsNativeDataTable(); var replacedRange = table.ReplaceData(dataTable); Assert.AreEqual("B3:G4", replacedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(2, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanReplaceToTableWithTablesRow1() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); table.SetShowTotalsRow(true); table.Fields.Last().TotalsRowFunction = XLTotalsRowFunction.Average; // Will cause table to overflow IEnumerable personEnumerable = NewData.Union(NewData).Union(NewData); var replacedRange = table.ReplaceData(personEnumerable); Assert.AreEqual("B3:G8", replacedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(6, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanReplaceToTableWithTablesRow2() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbook()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); table.SetShowTotalsRow(true); table.Fields.Last().TotalsRowFunction = XLTotalsRowFunction.Average; // Will cause table to shrink IEnumerable personEnumerable = NewData.Take(1); var replacedRange = table.ReplaceData(personEnumerable); Assert.AreEqual("B3:G3", replacedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(1, table.DataRange.RowCount()); Assert.AreEqual(6, table.DataRange.ColumnCount()); } } } [Test] public void CanReplaceWithUntypedEnumerableAndPropagateExtraColumns() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbookWithAdditionalColumns()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); var list = new ArrayList(); list.AddRange(NewData); list.AddRange(NewData); var replacedRange = table.ReplaceData(list, propagateExtraColumns: true); Assert.AreEqual("B3:G6", replacedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(4, table.DataRange.RowCount()); Assert.AreEqual(10, table.DataRange.ColumnCount()); Assert.AreEqual("SUM($G$3:G5)", table.Worksheet.Cell("H5").FormulaA1); Assert.AreEqual("SUM($G$3:G6)", table.Worksheet.Cell("H6").FormulaA1); Assert.AreEqual(100, table.Worksheet.Cell("H5").Value); Assert.AreEqual(130, table.Worksheet.Cell("H6").Value); Assert.AreEqual("LEN(B5)", table.Worksheet.Cell("I5").FormulaA1); Assert.AreEqual("LEN(B6)", table.Worksheet.Cell("I6").FormulaA1); Assert.AreEqual(16, table.Worksheet.Cell("I5").Value); Assert.AreEqual(21, table.Worksheet.Cell("I6").Value); Assert.AreEqual("G5>=40", table.Worksheet.Cell("J5").FormulaA1); Assert.AreEqual("G6>=40", table.Worksheet.Cell("J6").FormulaA1); Assert.AreEqual(false, table.Worksheet.Cell("J5").Value); Assert.AreEqual(false, table.Worksheet.Cell("J6").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K5").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K6").Value); } } } [Test] public void CanReplaceWithTypedEnumerableAndPropagateExtraColumns() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbookWithAdditionalColumns()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = NewData.Concat(NewData).OrderBy(p => p.Age); var replacedRange = table.ReplaceData(personEnumerable, propagateExtraColumns: true); Assert.AreEqual("B3:G6", replacedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(4, table.DataRange.RowCount()); Assert.AreEqual(10, table.DataRange.ColumnCount()); Assert.AreEqual("SUM($G$3:G5)", table.Worksheet.Cell("H5").FormulaA1); Assert.AreEqual("SUM($G$3:G6)", table.Worksheet.Cell("H6").FormulaA1); Assert.AreEqual(95, table.Worksheet.Cell("H5").Value); Assert.AreEqual(130, table.Worksheet.Cell("H6").Value); Assert.AreEqual("LEN(B5)", table.Worksheet.Cell("I5").FormulaA1); Assert.AreEqual("LEN(B6)", table.Worksheet.Cell("I6").FormulaA1); Assert.AreEqual(16, table.Worksheet.Cell("I5").Value); Assert.AreEqual(16, table.Worksheet.Cell("I6").Value); Assert.AreEqual("G5>=40", table.Worksheet.Cell("J5").FormulaA1); Assert.AreEqual("G6>=40", table.Worksheet.Cell("J6").FormulaA1); Assert.AreEqual(false, table.Worksheet.Cell("J5").Value); Assert.AreEqual(false, table.Worksheet.Cell("J6").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K5").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K6").Value); } } } [Test] public void CanAppendWithUntypedEnumerableAndPropagateExtraColumns() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbookWithAdditionalColumns()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); var list = new ArrayList(); list.AddRange(NewData); list.AddRange(NewData); var appendedRange = table.AppendData(list, propagateExtraColumns: true); Assert.AreEqual("B6:G9", appendedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(7, table.DataRange.RowCount()); Assert.AreEqual(10, table.DataRange.ColumnCount()); Assert.AreEqual("SUM($G$3:G8)", table.Worksheet.Cell("H8").FormulaA1); Assert.AreEqual("SUM($G$3:G9)", table.Worksheet.Cell("H9").FormulaA1); Assert.AreEqual(220, table.Worksheet.Cell("H8").Value); Assert.AreEqual(250, table.Worksheet.Cell("H9").Value); Assert.AreEqual("LEN(B8)", table.Worksheet.Cell("I8").FormulaA1); Assert.AreEqual("LEN(B9)", table.Worksheet.Cell("I9").FormulaA1); Assert.AreEqual(16, table.Worksheet.Cell("I8").Value); Assert.AreEqual(21, table.Worksheet.Cell("I9").Value); Assert.AreEqual("G8>=40", table.Worksheet.Cell("J8").FormulaA1); Assert.AreEqual("G9>=40", table.Worksheet.Cell("J9").FormulaA1); Assert.AreEqual(false, table.Worksheet.Cell("J8").Value); Assert.AreEqual(false, table.Worksheet.Cell("J9").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K8").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K9").Value); } } } [Test] public void CanAppendTypedEnumerableAndPropagateExtraColumns() { using (var ms = new MemoryStream()) { using (var wb = PrepareWorkbookWithAdditionalColumns()) { var ws = wb.Worksheets.First(); var table = ws.Tables.First(); IEnumerable personEnumerable = NewData .Concat(NewData) .Concat(NewData) .OrderBy(p => p.FirstName); var addedRange = table.AppendData(personEnumerable); Assert.AreEqual("B6:G11", addedRange.RangeAddress.ToString()); ws.Columns().AdjustToContents(); wb.SaveAs(ms); } using (var wb = new XLWorkbook(ms)) { var table = wb.Worksheets.SelectMany(ws => ws.Tables).First(); Assert.AreEqual(9, table.DataRange.RowCount()); Assert.AreEqual(10, table.DataRange.ColumnCount()); Assert.AreEqual("SUM($G$3:G10)", table.Worksheet.Cell("H10").FormulaA1); Assert.AreEqual("SUM($G$3:G11)", table.Worksheet.Cell("H11").FormulaA1); Assert.AreEqual(280, table.Worksheet.Cell("H10").Value); Assert.AreEqual(315, table.Worksheet.Cell("H11").Value); Assert.AreEqual("LEN(B10)", table.Worksheet.Cell("I10").FormulaA1); Assert.AreEqual("LEN(B11)", table.Worksheet.Cell("I11").FormulaA1); Assert.AreEqual(16, table.Worksheet.Cell("I10").Value); Assert.AreEqual(16, table.Worksheet.Cell("I11").Value); Assert.AreEqual("G10>=40", table.Worksheet.Cell("J10").FormulaA1); Assert.AreEqual("G11>=40", table.Worksheet.Cell("J11").FormulaA1); Assert.AreEqual(false, table.Worksheet.Cell("J10").Value); Assert.AreEqual(false, table.Worksheet.Cell("J11").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K10").Value); Assert.AreEqual("40 is not old!", table.Worksheet.Cell("K11").Value); } } } } }