Files
ClosedXML/ClosedXML_Tests/Excel/Ranges/MergedRangesTests.cs
T
Thom Lamb 2cd6df6481 Initial commit of the ClosedXML library
Establishes the foundational structure, core Excel functionality, and tooling.

- Implements base components for cells, ranges, columns, and rows.
- Integrates a custom calculation engine with a wide range of Excel functions.
- Adds comprehensive support for styling, conditional formatting, data validation, comments, pictures, and charts.
- Configures build setup, project metadata (NuGet), and developer guidelines.
- Includes editor and Git attributes for consistent code style and line endings.
2026-06-23 11:02:53 -05:00

444 lines
18 KiB
C#

using ClosedXML.Excel;
using NUnit.Framework;
using System.Linq;
namespace ClosedXML_Tests
{
[TestFixture]
public class MergedRangesTests
{
[Test]
public void LastCellFromMerge()
{
var wb = new XLWorkbook();
IXLWorksheet ws = wb.Worksheets.Add("Sheet");
ws.Range("B2:D4").Merge();
string first = ws.FirstCellUsed(XLCellsUsedOptions.All).Address.ToStringRelative();
string last = ws.LastCellUsed(XLCellsUsedOptions.All).Address.ToStringRelative();
Assert.AreEqual("B2", first);
Assert.AreEqual("D4", last);
}
[TestCase("A1:A2", "A1:A2")]
[TestCase("A2:B2", "A2:B2")]
[TestCase("A3:C3", "A3:E3")]
[TestCase("B4:B6", "B4:B6")]
[TestCase("C7:D7", "E7:F7")]
public void MergedRangesShiftedOnColumnInsert(string originalRange, string expectedRange)
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
var range = ws.Range(originalRange).Merge();
ws.Column(2).InsertColumnsAfter(2);
var mr = ws.MergedRanges.ToArray();
Assert.AreEqual(1, mr.Length);
Assert.AreSame(range, mr.Single());
Assert.AreEqual(expectedRange, range.RangeAddress.ToString());
}
}
[TestCase("A1:B1", "A1:B1")]
[TestCase("B1:B2", "B1:B2")]
[TestCase("C1:C3", "C1:C5")]
[TestCase("D2:F2", "D2:F2")]
[TestCase("G4:G5", "G6:G7")]
public void MergedRangesShiftedOnRowInsert(string originalRange, string expectedRange)
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
var range = ws.Range(originalRange).Merge();
ws.Row(2).InsertRowsBelow(2);
var mr = ws.MergedRanges.ToArray();
Assert.AreEqual(1, mr.Length);
Assert.AreSame(range, mr.Single());
Assert.AreEqual(expectedRange, range.RangeAddress.ToString());
}
}
[TestCase("A1:A2", true, "A1:A2")]
[TestCase("A2:B2", true, "A2:A2")]
[TestCase("A3:C3", true, "A3:B3")]
[TestCase("B4:B6", false, "")]
[TestCase("C7:D7", true, "B7:C7")]
public void MergedRangesShiftedOnColumnDelete(string originalRange, bool expectedExist, string expectedRange)
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
var range = ws.Range(originalRange).Merge();
ws.Column(2).Delete();
var mr = ws.MergedRanges.ToArray();
if (expectedExist)
{
Assert.AreEqual(1, mr.Length);
Assert.AreSame(range, mr.Single());
Assert.AreEqual(expectedRange, range.RangeAddress.ToString());
}
else
{
Assert.AreEqual(0, mr.Length);
Assert.IsFalse(range.RangeAddress.IsValid);
}
}
}
[TestCase("A1:B1", true, "A1:B1")]
[TestCase("B1:B2", true, "B1:B1")]
[TestCase("C1:C3", true, "C1:C2")]
[TestCase("D2:F2", false, "")]
[TestCase("G4:G5", true, "G3:G4")]
public void MergedRangesShiftedOnRowDelete(string originalRange, bool expectedExist, string expectedRange)
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
var range = ws.Range(originalRange).Merge();
ws.Row(2).Delete();
var mr = ws.MergedRanges.ToArray();
if (expectedExist)
{
Assert.AreEqual(1, mr.Length);
Assert.AreSame(range, mr.Single());
Assert.AreEqual(expectedRange, range.RangeAddress.ToString());
}
else
{
Assert.AreEqual(0, mr.Length);
Assert.IsFalse(range.RangeAddress.IsValid);
}
}
}
[Test]
public void ShiftRangeRightBreaksMerges()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
ws.Range("B2:C3").Merge();
ws.Range("B4:C5").Merge();
ws.Range("F2:G3").Merge(); // to be broken
ws.Range("F4:G5").Merge(); // to be broken
ws.Range("H1:I2").Merge();
ws.Range("H5:I6").Merge();
ws.Range("D3:E4").InsertColumnsAfter(2);
var mr = ws.MergedRanges.ToArray();
Assert.AreEqual(4, mr.Length);
Assert.AreEqual("H1:I2", mr[0].RangeAddress.ToString());
Assert.AreEqual("B2:C3", mr[1].RangeAddress.ToString());
Assert.AreEqual("B4:C5", mr[2].RangeAddress.ToString());
Assert.AreEqual("H5:I6", mr[3].RangeAddress.ToString());
}
}
[Test]
public void ShiftRangeLeftBreaksMerges()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
ws.Range("B2:C3").Merge();
ws.Range("B4:C5").Merge();
ws.Range("F2:G3").Merge(); // to be broken
ws.Range("F4:G5").Merge(); // to be broken
ws.Range("H1:I2").Merge();
ws.Range("H5:I6").Merge();
ws.Range("D3:E4").Delete(XLShiftDeletedCells.ShiftCellsLeft);
var mr = ws.MergedRanges.ToArray();
Assert.AreEqual(4, mr.Length);
Assert.AreEqual("H1:I2", mr[0].RangeAddress.ToString());
Assert.AreEqual("B2:C3", mr[1].RangeAddress.ToString());
Assert.AreEqual("B4:C5", mr[2].RangeAddress.ToString());
Assert.AreEqual("H5:I6", mr[3].RangeAddress.ToString());
}
}
[Test]
public void RangeShiftDownBreaksMerges()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
ws.Range("B2:C3").Merge();
ws.Range("D2:E3").Merge();
ws.Range("B6:C7").Merge(); // to be broken
ws.Range("D6:E7").Merge(); // to be broken
ws.Range("A8:B9").Merge();
ws.Range("E8:F9").Merge();
ws.Range("C4:D5").InsertRowsBelow(2);
var mr = ws.MergedRanges.ToArray();
Assert.AreEqual(4, mr.Length);
Assert.AreEqual("B2:C3", mr[0].RangeAddress.ToString());
Assert.AreEqual("D2:E3", mr[1].RangeAddress.ToString());
Assert.AreEqual("A8:B9", mr[2].RangeAddress.ToString());
Assert.AreEqual("E8:F9", mr[3].RangeAddress.ToString());
}
}
[Test]
public void RangeShiftUpBreaksMerges()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("MRShift");
ws.Range("B2:C3").Merge();
ws.Range("D2:E3").Merge();
ws.Range("B6:C7").Merge(); // to be broken
ws.Range("D6:E7").Merge(); // to be broken
ws.Range("A8:B9").Merge();
ws.Range("E8:F9").Merge();
ws.Range("C4:D5").Delete(XLShiftDeletedCells.ShiftCellsUp);
var mr = ws.MergedRanges.ToArray();
Assert.AreEqual(4, mr.Length);
Assert.AreEqual("B2:C3", mr[0].RangeAddress.ToString());
Assert.AreEqual("D2:E3", mr[1].RangeAddress.ToString());
Assert.AreEqual("A8:B9", mr[2].RangeAddress.ToString());
Assert.AreEqual("E8:F9", mr[3].RangeAddress.ToString());
}
}
[Test]
public void MergedCellsAcquireFirstCellStyle()
{
using (XLWorkbook wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
ws.Cell("A1").Style.Fill.BackgroundColor = XLColor.Red;
ws.Cell("A2").Style.Fill.BackgroundColor = XLColor.Yellow;
ws.Cell("A3").Style.Fill.BackgroundColor = XLColor.Green;
ws.Range("A1:A3").Merge();
Assert.AreEqual(XLColor.Red, ws.Cell("A1").Style.Fill.BackgroundColor);
Assert.AreEqual(XLColor.Red, ws.Cell("A2").Style.Fill.BackgroundColor);
Assert.AreEqual(XLColor.Red, ws.Cell("A3").Style.Fill.BackgroundColor);
}
}
[Test]
public void MergedCellsLooseData()
{
using (XLWorkbook wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
ws.Range("A1:A3").SetValue(100);
ws.Range("A1:A3").Merge();
Assert.AreEqual(100, ws.Cell("A1").Value);
Assert.AreEqual("", ws.Cell("A2").Value);
Assert.AreEqual("", ws.Cell("A3").Value);
}
}
[Test]
public void MergedCellsLooseConditionalFormats()
{
using (XLWorkbook wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
ws.Cell("A1").AddConditionalFormat().WhenContains("1").Fill.BackgroundColor = XLColor.Red;
ws.Cell("A2").AddConditionalFormat().WhenContains("2").Fill.BackgroundColor = XLColor.Yellow;
ws.Range("A1:A2").Merge();
Assert.AreEqual(1, ws.ConditionalFormats.Count());
Assert.AreEqual("A1:A1", ws.ConditionalFormats.Single().Ranges.Single().RangeAddress.ToString());
}
}
[Test]
public void MergedCellsLooseDataValidation()
{
using (XLWorkbook wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
ws.Cell("A1").NewDataValidation.WholeNumber.Between(1, 2);
ws.Cell("A2").NewDataValidation.Date.GreaterThan(new System.DateTime(2018, 1, 1));
ws.Range("A1:A2").Merge();
Assert.IsTrue(ws.Cell("A1").HasDataValidation);
Assert.AreEqual("1", ws.Cell("A1").DataValidation.MinValue);
Assert.AreEqual("2", ws.Cell("A1").DataValidation.MaxValue);
Assert.IsFalse(ws.Cell("A2").HasDataValidation);
}
}
[Test]
public void UnmergedCellsPreserveStyle()
{
using (XLWorkbook wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
var range = ws.Range("B2:D4");
range.Style.Fill.SetBackgroundColor(XLColor.Yellow);
range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick)
.Border.SetOutsideBorderColor(XLColor.DarkBlue)
.Border.SetInsideBorder(XLBorderStyleValues.Thin)
.Border.SetInsideBorderColor(XLColor.Pink);
range.Cells().ForEach(c => c.Value = c.Address.ToString());
var firstCell = ws.Cell("B2");
firstCell.Style.Fill.SetBackgroundColor(XLColor.Red)
.Alignment.SetHorizontal(XLAlignmentHorizontalValues.Center)
.Font.SetBold();
range.Merge();
range.Unmerge();
Assert.IsTrue(range.Cells().All(c => c.Style.Fill.BackgroundColor == XLColor.Red));
Assert.IsTrue(range.Cells().Where(c => c != firstCell).All(c => c.GetString().Length == 0));
Assert.AreEqual("B2", firstCell.Value);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("B2").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("B2").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("B2").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("B2").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("C2").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C2").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C2").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C2").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("D2").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("D2").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("D2").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("D2").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("B3").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("B3").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("B3").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("B3").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C3").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C3").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C3").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C3").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("D3").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("D3").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("D3").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("D3").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("B4").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("B4").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("B4").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("B4").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C4").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C4").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("C4").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("C4").Style.Border.LeftBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("D4").Style.Border.TopBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("D4").Style.Border.RightBorder);
Assert.AreEqual(XLBorderStyleValues.Thick, ws.Cell("D4").Style.Border.BottomBorder);
Assert.AreEqual(XLBorderStyleValues.None, ws.Cell("D4").Style.Border.LeftBorder);
}
}
[Test]
public void MergedRangesCellValuesShouldNotBeSet()
{
using (var workbook = new XLWorkbook())
{
var ws = workbook.AddWorksheet();
ws.Range("A2:A4").Merge();
ws.Cell("A2").Value = "1";
ws.Cell("A3").Value = "1";
ws.Cell("A4").Value = "1";
ws.Cell("B1").FormulaA1 = "SUM(A:A)";
Assert.AreEqual(1, ws.Cell("B1").Value);
}
using (var workbook = new XLWorkbook())
{
var ws = workbook.AddWorksheet();
ws.Range("A2:A4").Merge().SetValue(1);
ws.Cell("B1").FormulaA1 = "SUM(A:A)";
Assert.AreEqual(1, ws.Cell("B1").Value);
}
}
[Test]
public void MergedRangesCellFormulasShouldNotBeSet()
{
using (var workbook = new XLWorkbook())
{
var ws = workbook.AddWorksheet();
ws.Range("A2:A4").Merge();
ws.Cell("A2").FormulaA1 = "=1";
ws.Cell("A3").FormulaA1 = "=1";
ws.Cell("A4").FormulaA1 = "=1";
ws.Cell("B1").FormulaA1 = "SUM(A:A)";
Assert.AreEqual(1, ws.Cell("B1").Value);
}
using (var workbook = new XLWorkbook())
{
var ws = workbook.AddWorksheet();
ws.Range("A2:A4").Merge();
ws.Cell("A2").SetFormulaA1("=1");
ws.Cell("A3").SetFormulaA1("=1");
ws.Cell("A4").SetFormulaA1("=1");
ws.Cell("B1").SetFormulaA1("SUM(A:A)");
Assert.AreEqual(1, ws.Cell("B1").Value);
}
using (var workbook = new XLWorkbook())
{
var ws = workbook.AddWorksheet();
ws.Range("A2:A4").Merge();
ws.Cell("A2").FormulaR1C1 = "=1";
ws.Cell("A3").FormulaR1C1 = "=1";
ws.Cell("A4").FormulaR1C1 = "=1";
ws.Cell("B1").FormulaR1C1 = "SUM(A:A)";
Assert.AreEqual(1, ws.Cell("B1").Value);
}
using (var workbook = new XLWorkbook())
{
var ws = workbook.AddWorksheet();
ws.Range("A2:A4").Merge();
ws.Cell("A2").SetFormulaR1C1("=1");
ws.Cell("A3").SetFormulaR1C1("=1");
ws.Cell("A4").SetFormulaR1C1("=1");
ws.Cell("B1").SetFormulaR1C1("SUM(A:A)");
Assert.AreEqual(1, ws.Cell("B1").Value);
}
}
[Test]
public void MergeSingleCellRangeDoesNothing()
{
using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
var range = ws.Range(1, 1, 1, 1);
range.Merge();
Assert.IsFalse(range.IsMerged());
Assert.AreEqual(0, ws.MergedRanges.Count);
}
}
}