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.
This commit is contained in:
Thom Lamb
2026-06-23 11:02:53 -05:00
parent 28bc05cf54
commit 2cd6df6481
1092 changed files with 97270 additions and 408 deletions
@@ -0,0 +1,23 @@
using ClosedXML.Excel;
using NUnit.Framework;
namespace ClosedXML_Tests.Excel.CalcEngine
{
public class CalcEngineCellEnumerationTests
{
[Test]
public void CanEnumerateCellsOverEmptySheet()
{
using (var wb = new XLWorkbook())
{
var sheet1 = wb.AddWorksheet("Sheet1");
var sheet2 = wb.AddWorksheet("Sheet2");
var cell = sheet1.FirstCell();
cell.FormulaA1 = "=SUMIFS(Sheet2!B:B, Sheet2!C:C, 1)";
Assert.AreEqual(0, cell.Value);
}
}
}
}
@@ -0,0 +1,56 @@
using ClosedXML.Excel;
using ClosedXML.Excel.CalcEngine.Exceptions;
using NUnit.Framework;
using System;
using System.Globalization;
using System.Threading;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class CalcEngineExceptionTests
{
[OneTimeSetUp]
public void SetCultureInfo()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
}
[Test]
public void InvalidCharNumber()
{
Assert.Throws<CellValueException>(() => XLWorkbook.EvaluateExpr("CHAR(-2)"));
Assert.Throws<CellValueException>(() => XLWorkbook.EvaluateExpr("CHAR(270)"));
}
[Test]
public void DivisionByZero()
{
Assert.Throws<DivisionByZeroException>(() => XLWorkbook.EvaluateExpr("0/0"));
Assert.Throws<DivisionByZeroException>(() => new XLWorkbook().AddWorksheet().Evaluate("0/0"));
}
[Test]
public void InvalidFunction()
{
Exception ex;
ex = Assert.Throws<NameNotRecognizedException>(() => XLWorkbook.EvaluateExpr("XXX(A1:A2)"));
Assert.That(ex.Message, Is.EqualTo("The identifier `XXX` was not recognised."));
var ws = new XLWorkbook().AddWorksheet();
ex = Assert.Throws<NameNotRecognizedException>(() => ws.Evaluate("XXX(A1:A2)"));
Assert.That(ex.Message, Is.EqualTo("The identifier `XXX` was not recognised."));
}
[Test]
public void NestedNameNotRecognizedException()
{
using var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
ws.Cell("A1").SetFormulaA1("=XXX");
ws.Cell("A2").SetFormulaA1(@"=IFERROR(A1, ""Success"")");
Assert.AreEqual("Success", ws.Cell("A2").Value);
}
}
}
@@ -0,0 +1,564 @@
using ClosedXML.Excel;
using ClosedXML.Excel.CalcEngine.Exceptions;
using NUnit.Framework;
using System;
using System.Globalization;
using System.Threading;
namespace ClosedXML_Tests.Excel.DataValidations
{
/// <summary>
/// Summary description for UnitTest1
/// </summary>
[TestFixture]
public class DateAndTimeTests
{
[SetUp]
public void SetCultureInfo()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
}
[Test]
public void Date()
{
Object actual;
actual = XLWorkbook.EvaluateExpr("Date(2008, 1, 1)");
Assert.AreEqual(39448, actual);
actual = XLWorkbook.EvaluateExpr("Date(2008, 15, 1)");
Assert.AreEqual(39873, actual);
actual = XLWorkbook.EvaluateExpr("Date(2008, -50, 1)");
Assert.AreEqual(37895, actual);
actual = XLWorkbook.EvaluateExpr("Date(2008, 5, 63)");
Assert.AreEqual(39631, actual);
actual = XLWorkbook.EvaluateExpr("Date(2008, 13, 63)");
Assert.AreEqual(39876, actual);
actual = XLWorkbook.EvaluateExpr("Date(2008, 15, -120)");
Assert.AreEqual(39752, actual);
}
[TestCase("1/1/2006", "12/12/2010", "Y", ExpectedResult = 4)]
[TestCase("1/1/2006", "12/12/2010", "M", ExpectedResult = 59)]
[TestCase("1/1/2006", "12/12/2010", "D", ExpectedResult = 1806)]
[TestCase("1/1/2006", "12/12/2010", "MD", ExpectedResult = 11)]
[TestCase("1/1/2006", "12/12/2010", "YM", ExpectedResult = 11)]
[TestCase("1/1/2006", "12/12/2010", "YD", ExpectedResult = 345)]
[TestCase(38718, 40524, "Y", ExpectedResult = 4)]
[TestCase(38718, 40524, "M", ExpectedResult = 59)]
[TestCase(38718, 40524, "D", ExpectedResult = 1806)]
[TestCase(38718, 40524, "MD", ExpectedResult = 11)]
[TestCase(38718, 40524, "YM", ExpectedResult = 11)]
[TestCase(38718, 40524, "YD", ExpectedResult = 345)]
[TestCase("2001-12-31", "2002-4-15", "YM", ExpectedResult = 3)]
[TestCase("2001-12-10", "2002-4-15", "YM", ExpectedResult = 4)]
[TestCase("2001-12-15", "2002-4-15", "YM", ExpectedResult = 4)]
[TestCase("2001-12-31", "2002-4-15", "YD", ExpectedResult = 105)]
[TestCase("2001-12-31", "2003-4-15", "YD", ExpectedResult = 105)]
[TestCase("2002-01-31", "2002-4-15", "YD", ExpectedResult = 74)]
[TestCase("2001-12-02", "2001-12-15", "Y", ExpectedResult = 0)]
[TestCase("2001-12-02", "2002-12-02", "Y", ExpectedResult = 1)]
[TestCase("2006-01-15", "2006-03-14", "M", ExpectedResult = 1)]
[TestCase("2020-11-22", "2020-11-23 9:00", "D", ExpectedResult = 1)]
public double Datedif(object startDate, object endDate, string unit)
{
if (startDate is string s1) startDate = $"\"{s1}\"";
if (endDate is string s2) endDate = $"\"{s2}\"";
return (double)XLWorkbook.EvaluateExpr($"DATEDIF({startDate}, {endDate}, \"{unit}\")");
}
[TestCase("\"1/1/2010\"", "\"12/12/2006\"", "Y")]
[TestCase(40524, 38718, "Y")]
[TestCase("\"1/1/2006\"", "\"12/12/2010\"", "N")]
[TestCase(38718, 40524, "N")]
public void DatedifExceptions(object startDate, object endDate, string unit)
{
Assert.Throws<NumberException>(() => XLWorkbook.EvaluateExpr($"DATEDIF({startDate}, {endDate}, \"{unit}\")"));
}
[Test]
public void Datevalue()
{
Object actual = XLWorkbook.EvaluateExpr("DateValue(\"8/22/2008\")");
Assert.AreEqual(39682, actual);
}
[Test]
public void Day()
{
Object actual = XLWorkbook.EvaluateExpr("Day(\"8/22/2008\")");
Assert.AreEqual(22, actual);
}
[Test]
public void Days()
{
Object actual = XLWorkbook.EvaluateExpr("DAYS(DATE(2016,10,1),DATE(1992,2,29))");
Assert.AreEqual(8981, actual);
actual = XLWorkbook.EvaluateExpr("DAYS(\"2016-10-1\",\"1992-2-29\")");
Assert.AreEqual(8981, actual);
}
[Test]
public void DayWithDifferentCulture()
{
CultureInfo ci = new CultureInfo(CultureInfo.InvariantCulture.LCID);
ci.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = ci;
Object actual = XLWorkbook.EvaluateExpr("Day(\"1/6/2008\")");
Assert.AreEqual(1, actual);
}
[Test]
public void Days360_Default()
{
Object actual = XLWorkbook.EvaluateExpr("Days360(\"1/30/2008\", \"2/1/2008\")");
Assert.AreEqual(1, actual);
}
[Test]
public void Days360_Europe1()
{
Object actual = XLWorkbook.EvaluateExpr("DAYS360(\"1/1/2008\", \"3/31/2008\",TRUE)");
Assert.AreEqual(89, actual);
}
[Test]
public void Days360_Europe2()
{
Object actual = XLWorkbook.EvaluateExpr("DAYS360(\"3/31/2008\", \"1/1/2008\",TRUE)");
Assert.AreEqual(-89, actual);
}
[Test]
public void Days360_US1()
{
Object actual = XLWorkbook.EvaluateExpr("DAYS360(\"1/1/2008\", \"3/31/2008\",FALSE)");
Assert.AreEqual(90, actual);
}
[Test]
public void Days360_US2()
{
Object actual = XLWorkbook.EvaluateExpr("DAYS360(\"3/31/2008\", \"1/1/2008\",FALSE)");
Assert.AreEqual(-89, actual);
}
[Test]
public void EDate_Negative1()
{
Object actual = XLWorkbook.EvaluateExpr("EDate(\"3/1/2008\", -1)");
Assert.AreEqual(new DateTime(2008, 2, 1), actual);
}
[Test]
public void EDate_Negative2()
{
Object actual = XLWorkbook.EvaluateExpr("EDate(\"3/31/2008\", -1)");
Assert.AreEqual(new DateTime(2008, 2, 29), actual);
}
[Test]
public void EDate_Positive1()
{
Object actual = XLWorkbook.EvaluateExpr("EDate(\"3/1/2008\", 1)");
Assert.AreEqual(new DateTime(2008, 4, 1), actual);
}
[Test]
public void EDate_Positive2()
{
Object actual = XLWorkbook.EvaluateExpr("EDate(\"3/31/2008\", 1)");
Assert.AreEqual(new DateTime(2008, 4, 30), actual);
}
[Test]
public void EOMonth_Negative()
{
Object actual = XLWorkbook.EvaluateExpr("EOMonth(\"3/1/2008\", -1)");
Assert.AreEqual(new DateTime(2008, 2, 29), actual);
}
[Test]
public void EOMonth_Positive()
{
Object actual = XLWorkbook.EvaluateExpr("EOMonth(\"3/31/2008\", 1)");
Assert.AreEqual(new DateTime(2008, 4, 30), actual);
}
[Test]
public void Hour()
{
Object actual = XLWorkbook.EvaluateExpr("Hour(\"8/22/2008 3:30:45 PM\")");
Assert.AreEqual(15, actual);
}
[Test]
public void Minute()
{
Object actual = XLWorkbook.EvaluateExpr("Minute(\"8/22/2008 3:30:45 AM\")");
Assert.AreEqual(30, actual);
}
[Test]
public void Month()
{
Object actual = XLWorkbook.EvaluateExpr("Month(\"8/22/2008\")");
Assert.AreEqual(8, actual);
}
[Test]
public void IsoWeekNum()
{
Object actual = XLWorkbook.EvaluateExpr("ISOWEEKNUM(DATEVALUE(\"2012-3-9\"))");
Assert.AreEqual(10, actual);
actual = XLWorkbook.EvaluateExpr("ISOWEEKNUM(DATE(2012,12,31))");
Assert.AreEqual(1, actual);
}
[Test]
public void Networkdays_MultipleHolidaysGiven()
{
var wb = new XLWorkbook();
IXLWorksheet ws = wb.AddWorksheet("Sheet1");
ws.FirstCell().SetValue("Date")
.CellBelow().SetValue(new DateTime(2008, 10, 1))
.CellBelow().SetValue(new DateTime(2009, 3, 1))
.CellBelow().SetValue(new DateTime(2008, 11, 26))
.CellBelow().SetValue(new DateTime(2008, 12, 4))
.CellBelow().SetValue(new DateTime(2009, 1, 21));
Object actual = ws.Evaluate("Networkdays(A2,A3,A4:A6)");
Assert.AreEqual(105, actual);
}
[Test]
public void Networkdays_NoHolidaysGiven()
{
Object actual = XLWorkbook.EvaluateExpr("Networkdays(\"10/01/2008\", \"3/01/2009\")");
Assert.AreEqual(108, actual);
}
[Test]
public void Networkdays_NegativeResult()
{
Object actual = XLWorkbook.EvaluateExpr("Networkdays(\"3/01/2009\", \"10/01/2008\")");
Assert.AreEqual(-108, actual);
actual = XLWorkbook.EvaluateExpr("Networkdays(\"2016-01-01\", \"2015-12-23\")");
Assert.AreEqual(-8, actual);
}
[Test]
public void Networkdays_OneHolidaysGiven()
{
Object actual = XLWorkbook.EvaluateExpr("Networkdays(\"10/01/2008\", \"3/01/2009\", \"11/26/2008\")");
Assert.AreEqual(107, actual);
}
[Test]
public void Second()
{
Object actual = XLWorkbook.EvaluateExpr("Second(\"8/22/2008 3:30:45 AM\")");
Assert.AreEqual(45, actual);
}
[Test]
public void Time()
{
Object actual = XLWorkbook.EvaluateExpr("Time(1,2,3)");
Assert.AreEqual(new TimeSpan(1, 2, 3), actual);
}
[Test]
public void TimeValue1()
{
Object actual = XLWorkbook.EvaluateExpr("TimeValue(\"2:24 AM\")");
Assert.IsTrue(XLHelper.AreEqual(0.1, (double)actual));
}
[Test]
public void TimeValue2()
{
Object actual = XLWorkbook.EvaluateExpr("TimeValue(\"22-Aug-2008 6:35 AM\")");
Assert.IsTrue(XLHelper.AreEqual(0.27430555555555558, (double)actual));
}
[Test]
public void Today()
{
Object actual = XLWorkbook.EvaluateExpr("Today()");
Assert.AreEqual(DateTime.Now.Date, actual);
}
[Test]
public void Weekday_1()
{
Object actual = XLWorkbook.EvaluateExpr("Weekday(\"2/14/2008\", 1)");
Assert.AreEqual(5, actual);
}
[Test]
public void Weekday_2()
{
Object actual = XLWorkbook.EvaluateExpr("Weekday(\"2/14/2008\", 2)");
Assert.AreEqual(4, actual);
}
[Test]
public void Weekday_3()
{
Object actual = XLWorkbook.EvaluateExpr("Weekday(\"2/14/2008\", 3)");
Assert.AreEqual(3, actual);
}
[Test]
public void Weekday_Omitted()
{
Object actual = XLWorkbook.EvaluateExpr("Weekday(\"2/14/2008\")");
Assert.AreEqual(5, actual);
}
[Test]
public void Weeknum_1()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2000\", 1)"));
}
[Test]
public void Weeknum_10()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2004\", 2)"));
}
[Test]
public void Weeknum_11()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2005\", 1)"));
}
[Test]
public void Weeknum_12()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2005\", 2)"));
}
[Test]
public void Weeknum_13()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2006\", 1)"));
}
[Test]
public void Weeknum_14()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2006\", 2)"));
}
[Test]
public void Weeknum_15()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2007\", 1)"));
}
[Test]
public void Weeknum_16()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2007\", 2)"));
}
[Test]
public void Weeknum_17()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2008\", 1)"));
}
[Test]
public void Weeknum_18()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2008\", 2)"));
}
[Test]
public void Weeknum_19()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2009\", 1)"));
}
[Test]
public void Weeknum_2()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2000\", 2)"));
}
[Test]
public void Weeknum_20()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2009\", 2)"));
}
[Test]
public void Weeknum_3()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2001\", 1)"));
}
[Test]
public void Weeknum_4()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2001\", 2)"));
}
[Test]
public void Weeknum_5()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2002\", 1)"));
}
[Test]
public void Weeknum_6()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2002\", 2)"));
}
[Test]
public void Weeknum_7()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2003\", 1)"));
}
[Test]
public void Weeknum_8()
{
Assert.AreEqual(10, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2003\", 2)"));
}
[Test]
public void Weeknum_9()
{
Assert.AreEqual(11, XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2004\", 1)"));
}
[Test]
public void Weeknum_Default()
{
Object actual = XLWorkbook.EvaluateExpr("Weeknum(\"3/9/2008\")");
Assert.AreEqual(11, actual);
}
[Test]
public void Workdays_MultipleHolidaysGiven()
{
var wb = new XLWorkbook();
IXLWorksheet ws = wb.AddWorksheet("Sheet1");
ws.FirstCell().SetValue("Date")
.CellBelow().SetValue(new DateTime(2008, 10, 1))
.CellBelow().SetValue(151)
.CellBelow().SetValue(new DateTime(2008, 11, 26))
.CellBelow().SetValue(new DateTime(2008, 12, 4))
.CellBelow().SetValue(new DateTime(2009, 1, 21));
Object actual = ws.Evaluate("Workday(A2,A3,A4:A6)");
Assert.AreEqual(new DateTime(2009, 5, 5), actual);
}
[Test]
public void Workdays_NoHolidaysGiven()
{
Object actual = XLWorkbook.EvaluateExpr("Workday(\"10/01/2008\", 151)");
Assert.AreEqual(new DateTime(2009, 4, 30), actual);
actual = XLWorkbook.EvaluateExpr("Workday(\"2016-01-01\", -10)");
Assert.AreEqual(new DateTime(2015, 12, 18), actual);
}
[Test]
public void Workdays_OneHolidaysGiven()
{
Object actual = XLWorkbook.EvaluateExpr("Workday(\"10/01/2008\", 152, \"11/26/2008\")");
Assert.AreEqual(new DateTime(2009, 5, 4), actual);
}
[Test]
public void Year()
{
Object actual = XLWorkbook.EvaluateExpr("Year(\"8/22/2008\")");
Assert.AreEqual(2008, actual);
}
[Test]
public void Yearfrac_1_base0()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2008\",0)");
Assert.IsTrue(XLHelper.AreEqual(0.25, (double)actual));
}
[Test]
public void Yearfrac_1_base1()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2008\",1)");
Assert.IsTrue(XLHelper.AreEqual(0.24590163934426229, (double)actual));
}
[Test]
public void Yearfrac_1_base2()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2008\",2)");
Assert.IsTrue(XLHelper.AreEqual(0.25, (double)actual));
}
[Test]
public void Yearfrac_1_base3()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2008\",3)");
Assert.IsTrue(XLHelper.AreEqual(0.24657534246575341, (double)actual));
}
[Test]
public void Yearfrac_1_base4()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2008\",4)");
Assert.IsTrue(XLHelper.AreEqual(0.24722222222222223, (double)actual));
}
[Test]
public void Yearfrac_2_base0()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2013\",0)");
Assert.IsTrue(XLHelper.AreEqual(5.25, (double)actual));
}
[Test]
public void Yearfrac_2_base1()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2013\",1)");
Assert.IsTrue(XLHelper.AreEqual(5.24452554744526, (double)actual));
}
[Test]
public void Yearfrac_2_base2()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2013\",2)");
Assert.IsTrue(XLHelper.AreEqual(5.32222222222222, (double)actual));
}
[Test]
public void Yearfrac_2_base3()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2013\",3)");
Assert.IsTrue(XLHelper.AreEqual(5.24931506849315, (double)actual));
}
[Test]
public void Yearfrac_2_base4()
{
Object actual = XLWorkbook.EvaluateExpr("Yearfrac(\"1/1/2008\", \"3/31/2013\",4)");
Assert.IsTrue(XLHelper.AreEqual(5.24722222222222, (double)actual));
}
}
}
@@ -0,0 +1,391 @@
using ClosedXML.Excel;
using NUnit.Framework;
using System;
using System.Linq;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class FormulaCachingTests
{
[Test]
public void NewWorkbookDoesNotNeedRecalculation()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var cell = sheet.Cell(1, 1);
Assert.AreEqual(0, wb.RecalculationCounter);
Assert.IsFalse(cell.NeedsRecalculation);
}
}
[Test]
public void EditCellCausesCounterIncreasing()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var cell = sheet.Cell(1, 1);
cell.Value = "1234567";
Assert.Greater(wb.RecalculationCounter, 0);
}
}
[Test]
public void StaticCellDoesNotNeedRecalculation()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var cell = sheet.Cell(1, 1);
cell.Value = "1234567";
Assert.IsFalse(cell.NeedsRecalculation);
}
}
[Test]
public void EditCellInvalidatesDependentCells()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var cell = sheet.Cell(1, 1);
var dependentCell = sheet.Cell(2, 1);
dependentCell.FormulaA1 = "=A1";
var _ = dependentCell.Value;
cell.Value = "1234567";
Assert.IsTrue(dependentCell.NeedsRecalculation);
}
}
[Test]
public void EditFormulaA1InvalidatesDependentCells()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a1 = sheet.Cell("A1");
var a2 = sheet.Cell("A2");
var a3 = sheet.Cell("A3");
var a4 = sheet.Cell("A4");
a2.FormulaA1 = "=A1*10";
a3.FormulaA1 = "=A2*10";
a4.FormulaA1 = "=SUM(A1:A3)";
a1.Value = 15;
var res1 = a4.Value;
a2.FormulaA1 = "=A1*20";
var res2 = a4.Value;
Assert.AreEqual(15 + 150 + 1500, res1);
Assert.AreEqual(15 + 300 + 3000, res2);
}
}
[Test]
public void EditFormulaR1C1InvalidatesDependentCells()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a1 = sheet.Cell("A1");
var a2 = sheet.Cell("A2");
var a3 = sheet.Cell("A3");
var a4 = sheet.Cell("A4");
a2.FormulaA1 = "=A1*10";
a3.FormulaA1 = "=A2*10";
a4.FormulaA1 = "=SUM(A1:A3)";
a1.Value = 15;
var res1 = a4.Value;
a2.FormulaR1C1 = "=R[-1]C*2";
var res2 = a4.Value;
Assert.AreEqual(15 + 150 + 1500, res1);
Assert.AreEqual(15 + 30 + 300, res2);
}
}
[Test]
public void InsertRowInvalidatesValues()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a4 = sheet.Cell("A4");
a4.FormulaA1 = "=COUNTBLANK(A1:A3)";
var res1 = a4.Value;
sheet.Row(2).InsertRowsAbove(2);
var res2 = a4.Value;
Assert.AreEqual(3, res1);
Assert.AreEqual(5, res2);
}
}
[Test]
public void DeleteRowInvalidatesValues()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a4 = sheet.Cell("A4");
a4.FormulaA1 = "=COUNTBLANK(A1:A3)";
var res1 = a4.Value;
sheet.Row(2).Delete();
var res2 = a4.Value;
Assert.AreEqual(3, res1);
Assert.AreEqual(2, res2);
}
}
[Test]
public void ChainedCalculationPreservesIntermediateValues()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a1 = sheet.Cell("A1");
var a2 = sheet.Cell("A2");
var a3 = sheet.Cell("A3");
var a4 = sheet.Cell("A4");
a2.FormulaA1 = "=A1*10";
a3.FormulaA1 = "=A2*10";
a4.FormulaA1 = "=SUM(A1:A3)";
a1.Value = 15;
var res = a4.Value;
Assert.AreEqual(15 + 150 + 1500, res);
Assert.IsFalse(a4.NeedsRecalculation);
Assert.IsFalse(a3.NeedsRecalculation);
Assert.IsFalse(a2.NeedsRecalculation);
Assert.AreEqual(150, a2.CachedValue);
Assert.AreEqual(1500, a3.CachedValue);
Assert.AreEqual(15 + 150 + 1500, a4.CachedValue);
}
}
[Test]
public void EditingAffectsDependentCells()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a1 = sheet.Cell("A1");
var a2 = sheet.Cell("A2");
var a3 = sheet.Cell("A3");
var a4 = sheet.Cell("A4");
a2.FormulaA1 = "=A1*10";
a3.FormulaA1 = "=A2*10";
a4.FormulaA1 = "=SUM(A1:A3)";
a1.Value = 15;
var res1 = a4.Value;
a1.Value = 20;
var res2 = a4.Value;
Assert.AreEqual(15 + 150 + 1500, res1);
Assert.AreEqual(20 + 200 + 2000, res2);
}
}
[Test]
[TestCase("C4", new string[] { "C5" })]
[TestCase("D4", new string[] { })]
[TestCase("A1", new string[] { "A2", "A3", "A4", "C1", "C2", "C3", "C5" })]
[TestCase("B2", new string[] { "B3", "B4", "C2", "C3", "C5" })]
[TestCase("C2", new string[] { "C5" })]
public void EditingDoesNotAffectNonDependingCells(string changedCell, string[] affectedCells)
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
sheet.Cell("A2").FormulaA1 = "A1+1";
sheet.Cell("A3").FormulaA1 = "SUM(A1:A2)";
sheet.Cell("A4").FormulaA1 = "SUM(A1:A3)";
sheet.Cell("B2").FormulaA1 = "B1+1";
sheet.Cell("B3").FormulaA1 = "SUM(B1:B2)";
sheet.Cell("B4").FormulaA1 = "SUM(B1:B3)";
sheet.Cell("C1").FormulaA1 = "SUM(A1:B1)";
sheet.Cell("C2").FormulaA1 = "SUM(A2:B2)";
sheet.Cell("C3").FormulaA1 = "SUM(A3:B3)";
sheet.Cell("C5").FormulaA1 = "SUM($A$1:$C$4)";
sheet.RecalculateAllFormulas();
var allCells = sheet.CellsUsed();
sheet.Cell(changedCell).Value = 100;
var modifiedCells = allCells.Where(cell => cell.NeedsRecalculation);
Assert.AreEqual(affectedCells.Length, modifiedCells.Count());
foreach (var cellAddress in affectedCells)
{
Assert.IsTrue(modifiedCells.Any(cell => cell.Address.ToString() == cellAddress),
string.Format("Cell {0} is expected to need recalculation, but it does not", cellAddress));
}
}
}
[Test]
public void CircularReferenceFailsCalculating()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a1 = sheet.Cell("A1");
var a2 = sheet.Cell("A2");
var a3 = sheet.Cell("A3");
var a4 = sheet.Cell("A4");
a2.FormulaA1 = "=A1*10";
a3.FormulaA1 = "=A2*10";
a4.FormulaA1 = "=A3*10";
a1.FormulaA1 = "A2+A3+A4";
var getValueA1 = new TestDelegate(() => { var v = a1.Value; });
var getValueA2 = new TestDelegate(() => { var v = a2.Value; });
var getValueA3 = new TestDelegate(() => { var v = a3.Value; });
var getValueA4 = new TestDelegate(() => { var v = a4.Value; });
Assert.Throws(typeof(InvalidOperationException), getValueA1);
Assert.Throws(typeof(InvalidOperationException), getValueA2);
Assert.Throws(typeof(InvalidOperationException), getValueA3);
Assert.Throws(typeof(InvalidOperationException), getValueA4);
}
}
[Test]
public void CircularReferenceRecalculationNeededDoesNotFail()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var a1 = sheet.Cell("A1");
var a2 = sheet.Cell("A2");
var a3 = sheet.Cell("A3");
var a4 = sheet.Cell("A4");
a2.FormulaA1 = "=A1*10";
a3.FormulaA1 = "=A2*10";
a4.FormulaA1 = "=A3*10";
var _ = a4.Value;
a1.FormulaA1 = "=SUM(A2:A4)";
var recalcNeededA1 = a1.NeedsRecalculation;
var recalcNeededA2 = a2.NeedsRecalculation;
var recalcNeededA3 = a3.NeedsRecalculation;
var recalcNeededA4 = a4.NeedsRecalculation;
Assert.IsTrue(recalcNeededA1);
Assert.IsTrue(recalcNeededA2);
Assert.IsTrue(recalcNeededA3);
Assert.IsTrue(recalcNeededA4);
}
}
[Test]
public void DeleteWorksheetInvalidatesValues()
{
using (var wb = new XLWorkbook())
{
var sheet1 = wb.Worksheets.Add("Sheet1");
var sheet2 = wb.Worksheets.Add("Sheet2");
var sheet1_a1 = sheet1.Cell("A1");
var sheet2_a1 = sheet2.Cell("A1");
sheet1_a1.FormulaA1 = "Sheet2!A1";
sheet2_a1.Value = "TestValue";
var val1 = sheet1_a1.Value;
sheet2.Delete();
var getValue = new TestDelegate(() => { var val2 = sheet1_a1.Value; });
Assert.AreEqual("TestValue", val1.ToString());
Assert.Throws(typeof(ArgumentOutOfRangeException), getValue);
}
}
[Test]
public void TestValueCellsCachedValue()
{
using (var wb = new XLWorkbook())
{
var sheet = wb.Worksheets.Add("TestSheet");
var cell = sheet.Cell(1, 1);
var date = new DateTime(2018, 4, 19); ;
cell.Value = date;
Assert.AreEqual(XLDataType.DateTime, cell.DataType);
Assert.AreEqual(date, cell.CachedValue);
cell.DataType = XLDataType.Number;
Assert.AreEqual(XLDataType.Number, cell.DataType);
Assert.AreEqual(date.ToOADate(), cell.CachedValue);
}
}
[Test]
public void CachedValueToExternalWorkbook()
{
using (var stream = TestHelper.GetStreamFromResource(TestHelper.GetResourcePath(@"Other\ExternalLinks\WorkbookWithExternalLink.xlsx")))
using (var wb = new XLWorkbook(stream))
{
var ws = wb.Worksheets.First();
var cell = ws.Cell("B2");
Assert.IsFalse(cell.NeedsRecalculation);
Assert.IsTrue(cell.HasFormula);
// This will fail when we start supporting external links
Assert.IsTrue(cell.FormulaA1.StartsWith("[1]"));
Assert.AreEqual("hello world", cell.CachedValue);
Assert.AreEqual("hello world", cell.Value);
Assert.AreEqual(11, ws.Evaluate("LEN(B2)"));
Assert.Throws<ArgumentOutOfRangeException>(() => wb.RecalculateAllFormulas());
}
}
[Test]
public void ChangingDataTypeChangesCachedValue()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Test");
ws.Cell(1, 1).Value = new DateTime(2019, 1, 1, 14, 0, 0);
ws.Cell(1, 2).Value = new DateTime(2019, 1, 1, 17, 45, 0);
var cell = ws.Cell(1, 3);
cell.FormulaA1 = "=B1-A1";
cell.Style.DateFormat.Format = "hh:mm";
Assert.IsNull(cell.CachedValue);
double value = (double)cell.Value;
Assert.AreEqual(value, cell.CachedValue);
cell.DataType = XLDataType.DateTime;
Assert.AreEqual(DateTime.FromOADate(value), cell.CachedValue);
Assert.AreEqual("03:45", cell.GetFormattedString());
cell.DataType = XLDataType.Number;
Assert.AreEqual(value, (double)cell.CachedValue, 1e-10);
Assert.AreEqual("0.15625", cell.GetFormattedString());
cell.DataType = XLDataType.TimeSpan;
Assert.AreEqual(TimeSpan.FromDays(value), (TimeSpan)cell.CachedValue);
Assert.AreEqual("03:45:00", cell.GetFormattedString()); // I think the seconds in this string is due to a shortcoming in the ExcelNumberFormat library
}
}
}
}
@@ -0,0 +1,754 @@
using ClosedXML.Excel;
using NUnit.Framework;
using System;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class FunctionsTests
{
[SetUp]
public void Init()
{
// Make sure tests run on a deterministic culture
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
}
[Test]
public void Asc()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Asc(""Text"")");
Assert.AreEqual("Text", actual);
}
[Test]
public void Clean()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(String.Format(@"Clean(""A{0}B"")", Environment.NewLine));
Assert.AreEqual("AB", actual);
}
[Test]
public void Combin()
{
object actual1 = XLWorkbook.EvaluateExpr("Combin(200, 2)");
Assert.AreEqual(19900.0, actual1);
object actual2 = XLWorkbook.EvaluateExpr("Combin(20.1, 2.9)");
Assert.AreEqual(190.0, actual2);
}
[Test]
public void Degrees()
{
object actual1 = XLWorkbook.EvaluateExpr("Degrees(180)");
Assert.IsTrue(Math.PI - (double)actual1 < XLHelper.Epsilon);
}
[Test]
public void Dollar()
{
object actual = XLWorkbook.EvaluateExpr("Dollar(12345.123)");
Assert.AreEqual(TestHelper.CurrencySymbol + "12,345.12", actual);
actual = XLWorkbook.EvaluateExpr("Dollar(12345.123, 1)");
Assert.AreEqual(TestHelper.CurrencySymbol + "12,345.1", actual);
}
[Test]
public void Even()
{
object actual = XLWorkbook.EvaluateExpr("Even(3)");
Assert.AreEqual(4, actual);
actual = XLWorkbook.EvaluateExpr("Even(2)");
Assert.AreEqual(2, actual);
actual = XLWorkbook.EvaluateExpr("Even(-1)");
Assert.AreEqual(-2, actual);
actual = XLWorkbook.EvaluateExpr("Even(-2)");
Assert.AreEqual(-2, actual);
actual = XLWorkbook.EvaluateExpr("Even(0)");
Assert.AreEqual(0, actual);
actual = XLWorkbook.EvaluateExpr("Even(1.5)");
Assert.AreEqual(2, actual);
actual = XLWorkbook.EvaluateExpr("Even(2.01)");
Assert.AreEqual(4, actual);
}
[Test]
public void Exact()
{
Object actual;
actual = XLWorkbook.EvaluateExpr("Exact(\"A\", \"A\")");
Assert.AreEqual(true, actual);
actual = XLWorkbook.EvaluateExpr("Exact(\"A\", \"a\")");
Assert.AreEqual(false, actual);
}
[Test]
public void Fact()
{
object actual = XLWorkbook.EvaluateExpr("Fact(5.9)");
Assert.AreEqual(120.0, actual);
}
[Test]
public void FactDouble()
{
object actual1 = XLWorkbook.EvaluateExpr("FactDouble(6)");
Assert.AreEqual(48.0, actual1);
object actual2 = XLWorkbook.EvaluateExpr("FactDouble(7)");
Assert.AreEqual(105.0, actual2);
}
[Test]
public void Fixed()
{
Object actual;
actual = XLWorkbook.EvaluateExpr("Fixed(12345.123)");
Assert.AreEqual("12,345.12", actual);
actual = XLWorkbook.EvaluateExpr("Fixed(12345.123, 1)");
Assert.AreEqual("12,345.1", actual);
actual = XLWorkbook.EvaluateExpr("Fixed(12345.123, 1, TRUE)");
Assert.AreEqual("12345.1", actual);
}
[Test]
public void Formula_from_another_sheet()
{
var wb = new XLWorkbook();
IXLWorksheet ws1 = wb.AddWorksheet("ws1");
ws1.FirstCell().SetValue(1).CellRight().SetFormulaA1("A1 + 1");
IXLWorksheet ws2 = wb.AddWorksheet("ws2");
ws2.FirstCell().SetFormulaA1("ws1!B1 + 1");
object v = ws2.FirstCell().Value;
Assert.AreEqual(3.0, v);
}
[Test]
public void Gcd()
{
object actual = XLWorkbook.EvaluateExpr("Gcd(24, 36)");
Assert.AreEqual(12, actual);
object actual1 = XLWorkbook.EvaluateExpr("Gcd(5, 0)");
Assert.AreEqual(5, actual1);
object actual2 = XLWorkbook.EvaluateExpr("Gcd(0, 5)");
Assert.AreEqual(5, actual2);
object actual3 = XLWorkbook.EvaluateExpr("Gcd(240, 360, 30)");
Assert.AreEqual(30, actual3);
}
[Test]
public void Lcm()
{
object actual = XLWorkbook.EvaluateExpr("Lcm(24, 36)");
Assert.AreEqual(72, actual);
object actual1 = XLWorkbook.EvaluateExpr("Lcm(5, 0)");
Assert.AreEqual(0, actual1);
object actual2 = XLWorkbook.EvaluateExpr("Lcm(0, 5)");
Assert.AreEqual(0, actual2);
object actual3 = XLWorkbook.EvaluateExpr("Lcm(240, 360, 30)");
Assert.AreEqual(720, actual3);
}
[Test]
public void MDetem()
{
IXLWorksheet ws = new XLWorkbook().AddWorksheet("Sheet1");
ws.Cell("A1").SetValue(2).CellRight().SetValue(4);
ws.Cell("A2").SetValue(3).CellRight().SetValue(5);
Object actual;
ws.Cell("A5").FormulaA1 = "MDeterm(A1:B2)";
actual = ws.Cell("A5").Value;
Assert.IsTrue(XLHelper.AreEqual(-2.0, (double)actual));
ws.Cell("A6").FormulaA1 = "Sum(A5)";
actual = ws.Cell("A6").Value;
Assert.IsTrue(XLHelper.AreEqual(-2.0, (double)actual));
ws.Cell("A7").FormulaA1 = "Sum(MDeterm(A1:B2))";
actual = ws.Cell("A7").Value;
Assert.IsTrue(XLHelper.AreEqual(-2.0, (double)actual));
}
[Test]
public void MInverse()
{
IXLWorksheet ws = new XLWorkbook().AddWorksheet("Sheet1");
ws.Cell("A1").SetValue(1).CellRight().SetValue(2).CellRight().SetValue(1);
ws.Cell("A2").SetValue(3).CellRight().SetValue(4).CellRight().SetValue(-1);
ws.Cell("A3").SetValue(0).CellRight().SetValue(2).CellRight().SetValue(0);
Object actual;
ws.Cell("A5").FormulaA1 = "MInverse(A1:C3)";
actual = ws.Cell("A5").Value;
Assert.IsTrue(XLHelper.AreEqual(0.25, (double)actual));
ws.Cell("A6").FormulaA1 = "Sum(A5)";
actual = ws.Cell("A6").Value;
Assert.IsTrue(XLHelper.AreEqual(0.25, (double)actual));
ws.Cell("A7").FormulaA1 = "Sum(MInverse(A1:C3))";
actual = ws.Cell("A7").Value;
Assert.IsTrue(XLHelper.AreEqual(0.5, (double)actual));
}
[Test]
public void MMult()
{
IXLWorksheet ws = new XLWorkbook().AddWorksheet("Sheet1");
ws.Cell("A1").SetValue(2).CellRight().SetValue(4);
ws.Cell("A2").SetValue(3).CellRight().SetValue(5);
ws.Cell("A3").SetValue(2).CellRight().SetValue(4);
ws.Cell("A4").SetValue(3).CellRight().SetValue(5);
Object actual;
ws.Cell("A5").FormulaA1 = "MMult(A1:B2, A3:B4)";
actual = ws.Cell("A5").Value;
Assert.AreEqual(16.0, actual);
ws.Cell("A6").FormulaA1 = "Sum(A5)";
actual = ws.Cell("A6").Value;
Assert.AreEqual(16.0, actual);
ws.Cell("A7").FormulaA1 = "Sum(MMult(A1:B2, A3:B4))";
actual = ws.Cell("A7").Value;
Assert.AreEqual(102.0, actual);
}
[Test]
public void Mod()
{
object actual = XLWorkbook.EvaluateExpr("Mod(3, 2)");
Assert.AreEqual(1, actual);
object actual1 = XLWorkbook.EvaluateExpr("Mod(-3, 2)");
Assert.AreEqual(1, actual1);
object actual2 = XLWorkbook.EvaluateExpr("Mod(3, -2)");
Assert.AreEqual(-1, actual2);
object actual3 = XLWorkbook.EvaluateExpr("Mod(-3, -2)");
Assert.AreEqual(-1, actual3);
}
[Test]
public void Multinomial()
{
object actual = XLWorkbook.EvaluateExpr("Multinomial(2,3,4)");
Assert.AreEqual(1260.0, actual);
}
[Test]
public void Odd()
{
object actual = XLWorkbook.EvaluateExpr("Odd(1.5)");
Assert.AreEqual(3, actual);
object actual1 = XLWorkbook.EvaluateExpr("Odd(3)");
Assert.AreEqual(3, actual1);
object actual2 = XLWorkbook.EvaluateExpr("Odd(2)");
Assert.AreEqual(3, actual2);
object actual3 = XLWorkbook.EvaluateExpr("Odd(-1)");
Assert.AreEqual(-1, actual3);
object actual4 = XLWorkbook.EvaluateExpr("Odd(-2)");
Assert.AreEqual(-3, actual4);
actual = XLWorkbook.EvaluateExpr("Odd(0)");
Assert.AreEqual(1, actual);
}
[Test]
public void Product()
{
object actual = XLWorkbook.EvaluateExpr("Product(2,3,4)");
Assert.AreEqual(24.0, actual);
}
[Test]
public void Quotient()
{
object actual = XLWorkbook.EvaluateExpr("Quotient(5,2)");
Assert.AreEqual(2, actual);
actual = XLWorkbook.EvaluateExpr("Quotient(4.5,3.1)");
Assert.AreEqual(1, actual);
actual = XLWorkbook.EvaluateExpr("Quotient(-10,3)");
Assert.AreEqual(-3, actual);
}
[Test]
public void Radians()
{
object actual = XLWorkbook.EvaluateExpr("Radians(270)");
Assert.IsTrue(Math.Abs(4.71238898038469 - (double)actual) < XLHelper.Epsilon);
}
[Test]
public void Roman()
{
object actual = XLWorkbook.EvaluateExpr("Roman(3046, 1)");
Assert.AreEqual("MMMXLVI", actual);
actual = XLWorkbook.EvaluateExpr("Roman(270)");
Assert.AreEqual("CCLXX", actual);
actual = XLWorkbook.EvaluateExpr("Roman(3999, true)");
Assert.AreEqual("MMMCMXCIX", actual);
}
[Test]
public void Round()
{
object actual = XLWorkbook.EvaluateExpr("Round(2.15, 1)");
Assert.AreEqual(2.2, actual);
actual = XLWorkbook.EvaluateExpr("Round(2.149, 1)");
Assert.AreEqual(2.1, actual);
actual = XLWorkbook.EvaluateExpr("Round(-1.475, 2)");
Assert.AreEqual(-1.48, actual);
actual = XLWorkbook.EvaluateExpr("Round(21.5, -1)");
Assert.AreEqual(20.0, actual);
actual = XLWorkbook.EvaluateExpr("Round(626.3, -3)");
Assert.AreEqual(1000.0, actual);
actual = XLWorkbook.EvaluateExpr("Round(1.98, -1)");
Assert.AreEqual(0.0, actual);
actual = XLWorkbook.EvaluateExpr("Round(-50.55, -2)");
Assert.AreEqual(-100.0, actual);
actual = XLWorkbook.EvaluateExpr("ROUND(59 * 0.535, 2)"); // (59 * 0.535) = 31.565
Assert.AreEqual(31.57, actual);
actual = XLWorkbook.EvaluateExpr("ROUND(59 * -0.535, 2)"); // (59 * -0.535) = -31.565
Assert.AreEqual(-31.57, actual);
}
[Test]
public void RoundDown()
{
object actual = XLWorkbook.EvaluateExpr("RoundDown(3.2, 0)");
Assert.AreEqual(3.0, actual);
actual = XLWorkbook.EvaluateExpr("RoundDown(76.9, 0)");
Assert.AreEqual(76.0, actual);
actual = XLWorkbook.EvaluateExpr("RoundDown(3.14159, 3)");
Assert.AreEqual(3.141, actual);
actual = XLWorkbook.EvaluateExpr("RoundDown(-3.14159, 1)");
Assert.AreEqual(-3.1, actual);
actual = XLWorkbook.EvaluateExpr("RoundDown(31415.92654, -2)");
Assert.AreEqual(31400.0, actual);
actual = XLWorkbook.EvaluateExpr("RoundDown(0, 3)");
Assert.AreEqual(0.0, actual);
}
[Test]
public void RoundUp()
{
object actual = XLWorkbook.EvaluateExpr("RoundUp(3.2, 0)");
Assert.AreEqual(4.0, actual);
actual = XLWorkbook.EvaluateExpr("RoundUp(76.9, 0)");
Assert.AreEqual(77.0, actual);
actual = XLWorkbook.EvaluateExpr("RoundUp(3.14159, 3)");
Assert.AreEqual(3.142, actual);
actual = XLWorkbook.EvaluateExpr("RoundUp(-3.14159, 1)");
Assert.AreEqual(-3.2, actual);
actual = XLWorkbook.EvaluateExpr("RoundUp(31415.92654, -2)");
Assert.AreEqual(31500.0, actual);
actual = XLWorkbook.EvaluateExpr("RoundUp(0, 3)");
Assert.AreEqual(0.0, actual);
}
[Test]
public void SeriesSum()
{
object actual = XLWorkbook.EvaluateExpr("SERIESSUM(2,3,4,5)");
Assert.AreEqual(40.0, actual);
var wb = new XLWorkbook();
IXLWorksheet ws = wb.AddWorksheet("Sheet1");
ws.Cell("A2").FormulaA1 = "PI()/4";
ws.Cell("A3").Value = 1;
ws.Cell("A4").FormulaA1 = "-1/FACT(2)";
ws.Cell("A5").FormulaA1 = "1/FACT(4)";
ws.Cell("A6").FormulaA1 = "-1/FACT(6)";
actual = ws.Evaluate("SERIESSUM(A2,0,2,A3:A6)");
Assert.IsTrue(Math.Abs(0.70710321482284566 - (double)actual) < XLHelper.Epsilon);
}
[Test]
public void SqrtPi()
{
object actual = XLWorkbook.EvaluateExpr("SqrtPi(1)");
Assert.IsTrue(Math.Abs(1.7724538509055159 - (double)actual) < XLHelper.Epsilon);
actual = XLWorkbook.EvaluateExpr("SqrtPi(2)");
Assert.IsTrue(Math.Abs(2.5066282746310002 - (double)actual) < XLHelper.Epsilon);
}
[Test]
public void SubtotalAverage()
{
object actual = XLWorkbook.EvaluateExpr("Subtotal(1,2,3)");
Assert.AreEqual(2.5, actual);
actual = XLWorkbook.EvaluateExpr(@"Subtotal(1,""A"",3, 2)");
Assert.AreEqual(2.5, actual);
}
[Test]
public void SubtotalCount()
{
object actual = XLWorkbook.EvaluateExpr("Subtotal(2,2,3)");
Assert.AreEqual(2, actual);
actual = XLWorkbook.EvaluateExpr(@"Subtotal(2,""A"",3)");
Assert.AreEqual(1, actual);
}
[Test]
public void SubtotalCountA()
{
Object actual;
actual = XLWorkbook.EvaluateExpr("Subtotal(3,2,3)");
Assert.AreEqual(2.0, actual);
actual = XLWorkbook.EvaluateExpr(@"Subtotal(3,"""",3)");
Assert.AreEqual(1.0, actual);
}
[Test]
public void SubtotalMax()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(4,2,3,""A"")");
Assert.AreEqual(3.0, actual);
}
[Test]
public void SubtotalMin()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(5,2,3,""A"")");
Assert.AreEqual(2.0, actual);
}
[Test]
public void SubtotalProduct()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(6,2,3,""A"")");
Assert.AreEqual(6.0, actual);
}
[Test]
public void SubtotalStDev()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(7,2,3,""A"")");
Assert.IsTrue(Math.Abs(0.70710678118654757 - (double)actual) < XLHelper.Epsilon);
}
[Test]
public void SubtotalStDevP()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(8,2,3,""A"")");
Assert.AreEqual(0.5, actual);
}
[Test]
public void SubtotalSum()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(9,2,3,""A"")");
Assert.AreEqual(5.0, actual);
}
[Test]
public void SubtotalVar()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(10,2,3,""A"")");
Assert.IsTrue(Math.Abs(0.5 - (double)actual) < XLHelper.Epsilon);
}
[Test]
public void SubtotalVarP()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"Subtotal(11,2,3,""A"")");
Assert.AreEqual(0.25, actual);
}
[Test]
public void SubtotalCalc()
{
var wb = new XLWorkbook();
var ws = wb.AddWorksheet();
ws.NamedRanges.Add("subtotalrange", "A37:A38");
ws.Cell("A1").Value = 2;
ws.Cell("A2").Value = 4;
ws.Cell("A3").FormulaA1 = "SUBTOTAL(9, A1:A2)"; // simple add subtotal
ws.Cell("A4").Value = 8;
ws.Cell("A5").Value = 16;
ws.Cell("A6").FormulaA1 = "SUBTOTAL(9, A4:A5)"; // simple add subtotal
ws.Cell("A7").Value = 32;
ws.Cell("A8").Value = 64;
ws.Cell("A9").FormulaA1 = "SUM(A7:A8)"; // func but not subtotal
ws.Cell("A10").Value = 128;
ws.Cell("A11").Value = 256;
ws.Cell("A12").FormulaA1 = "SUBTOTAL(1, A10:A11)"; // simple avg subtotal
ws.Cell("A13").Value = 512;
ws.Cell("A14").FormulaA1 = "SUBTOTAL(9, A1:A13)"; // subtotals in range
ws.Cell("A15").Value = 1024;
ws.Cell("A16").Value = 2048;
ws.Cell("A17").FormulaA1 = "42 + SUBTOTAL(9, A15:A16)"; // simple add subtotal in formula
ws.Cell("A18").Value = 4096;
ws.Cell("A19").FormulaA1 = "SUBTOTAL(9, A15:A18)"; // subtotals in range
ws.Cell("A20").Value = 8192;
ws.Cell("A21").Value = 16384;
ws.Cell("A22").FormulaA1 = @"32768 * SEARCH(""SUBTOTAL(9, A1:A2)"", A28)"; // subtotal literal in formula
ws.Cell("A23").FormulaA1 = "SUBTOTAL(9, A20:A22)"; // subtotal literal in formula in range
ws.Cell("A24").Value = 65536;
ws.Cell("A25").FormulaA1 = "A23"; // link to subtotal
ws.Cell("A26").FormulaA1 = "PRODUCT(SUBTOTAL(9, A24:A25), 2)"; // subtotal as parameter in func
ws.Cell("A27").Value = 131072;
ws.Cell("A28").Value = "SUBTOTAL(9, A1:A2)"; // subtotal literal
ws.Cell("A29").FormulaA1 = "SUBTOTAL(9, A27:A28)"; // subtotal literal in range
ws.Cell("A30").FormulaA1 = "SUBTOTAL(9, A31:A32)"; // simple add subtotal backward
ws.Cell("A31").Value = 262144;
ws.Cell("A32").Value = 524288;
ws.Cell("A33").FormulaA1 = "SUBTOTAL(9, A20:A32)"; // subtotals in range
ws.Cell("A34").FormulaA1 = @"SUBTOTAL(VALUE(""9""), A1:A33, A35:A41)"; // func as parameter in subtotal and many ranges
ws.Cell("A35").Value = 1048576;
ws.Cell("A36").FormulaA1 = "SUBTOTAL(9, A31:A32, A35)"; // many ranges
ws.Cell("A37").Value = 2097152;
ws.Cell("A38").Value = 4194304;
ws.Cell("A39").FormulaA1 = "SUBTOTAL(3*3, subtotalrange)"; // formula as parameter in subtotal and named range
ws.Cell("A40").Value = 8388608;
ws.Cell("A41").FormulaA1 = "PRODUCT(SUBTOTAL(A4+1, A35:A40), 2)"; // formula with link as parameter in subtotal
ws.Cell("A42").FormulaA1 = "PRODUCT(SUBTOTAL(A4+1, A35:A40), 2) + SUBTOTAL(A4+1, A35:A40)"; // two subtotals in one formula
Assert.AreEqual(6, ws.Cell("A3").Value);
Assert.AreEqual(24, ws.Cell("A6").Value);
Assert.AreEqual(192, ws.Cell("A12").Value);
Assert.AreEqual(1118, ws.Cell("A14").Value);
Assert.AreEqual(3114, ws.Cell("A17").Value);
Assert.AreEqual(7168, ws.Cell("A19").Value);
Assert.AreEqual(57344, ws.Cell("A23").Value);
Assert.AreEqual(245760, ws.Cell("A26").Value);
Assert.AreEqual(131072, ws.Cell("A29").Value);
Assert.AreEqual(786432, ws.Cell("A30").Value);
Assert.AreEqual(1097728, ws.Cell("A33").Value);
Assert.AreEqual(16834654, ws.Cell("A34").Value);
Assert.AreEqual(1835008, ws.Cell("A36").Value);
Assert.AreEqual(6291456, ws.Cell("A39").Value);
Assert.AreEqual(31457280, ws.Cell("A41").Value);
Assert.AreEqual(47185920, ws.Cell("A42").Value);
}
[Test]
public void Sum()
{
IXLCell cell = new XLWorkbook().AddWorksheet("Sheet1").FirstCell();
IXLCell fCell = cell.SetValue(1).CellBelow().SetValue(2).CellBelow();
fCell.FormulaA1 = "sum(A1:A2)";
Assert.AreEqual(3.0, fCell.Value);
}
[Test]
public void SumDateTimeAndNumber()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
ws.Cell("A1").Value = 1;
ws.Cell("A2").Value = new DateTime(2018, 1, 1);
Assert.AreEqual(43102, ws.Evaluate("SUM(A1:A2)"));
ws.Cell("A1").Value = 2;
ws.Cell("A2").FormulaA1 = "DATE(2018,1,1)";
Assert.AreEqual(43103, ws.Evaluate("SUM(A1:A2)"));
}
}
[Test]
public void SumSq()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"SumSq(3,4)");
Assert.AreEqual(25.0, actual);
}
[Test]
public void TextConcat()
{
var wb = new XLWorkbook();
IXLWorksheet ws = wb.AddWorksheet("Sheet1");
ws.Cell("A1").Value = 1;
ws.Cell("A2").Value = 1;
ws.Cell("B1").Value = 1;
ws.Cell("B2").Value = 1;
ws.Cell("C1").FormulaA1 = "\"The total value is: \" & SUM(A1:B2)";
object r = ws.Cell("C1").Value;
Assert.AreEqual("The total value is: 4", r.ToString());
}
[Test]
public void Trim()
{
Assert.AreEqual("Test", XLWorkbook.EvaluateExpr("Trim(\"Test \")"));
//Should not trim non breaking space
//See http://office.microsoft.com/en-us/excel-help/trim-function-HP010062581.aspx
Assert.AreEqual("Test\u00A0", XLWorkbook.EvaluateExpr("Trim(\"Test\u00A0 \")"));
}
[Test]
public void TestEmptyTallyOperations()
{
//In these test no values have been set
XLWorkbook wb = new XLWorkbook();
wb.Worksheets.Add("TallyTests");
var cell = wb.Worksheet(1).Cell(1, 1).SetFormulaA1("=MAX(D1,D2)");
Assert.AreEqual(0, cell.Value);
cell = wb.Worksheet(1).Cell(2, 1).SetFormulaA1("=MIN(D1,D2)");
Assert.AreEqual(0, cell.Value);
cell = wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=SUM(D1,D2)");
Assert.AreEqual(0, cell.Value);
Assert.That(() => wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=AVERAGE(D1,D2)").Value, Throws.TypeOf<ApplicationException>());
}
[Test]
public void TestOmittedParameters()
{
using (var wb = new XLWorkbook())
{
object value;
value = wb.Evaluate("=IF(TRUE,1)");
Assert.AreEqual(1, value);
value = wb.Evaluate("=IF(TRUE,1,)");
Assert.AreEqual(1, value);
value = wb.Evaluate("=IF(FALSE,1,)");
Assert.AreEqual(false, value);
value = wb.Evaluate("=IF(FALSE,,2)");
Assert.AreEqual(2, value);
}
}
[Test]
public void TestDefaultExcelFunctionNamespace()
{
Assert.DoesNotThrow(() => XLWorkbook.EvaluateExpr("TODAY()"));
Assert.DoesNotThrow(() => XLWorkbook.EvaluateExpr("_xlfn.TODAY()"));
Assert.IsTrue((bool)XLWorkbook.EvaluateExpr("_xlfn.TODAY() = TODAY()"));
}
[TestCase("=1234%", 12.34)]
[TestCase("=1234%%", 0.1234)]
[TestCase("=100+200%", 102.0)]
[TestCase("=100%+200", 201.0)]
[TestCase("=(100+200)%", 3.0)]
[TestCase("=200%^5", 32.0)]
[TestCase("=200%^400%", 16.0)]
[TestCase("=SUM(100,200,300)%", 6.0)]
public void PercentOperator(string formula, double expectedResult)
{
var res = (double)XLWorkbook.EvaluateExpr(formula);
Assert.AreEqual(expectedResult, res, XLHelper.Epsilon);
}
[TestCase("=--1", 1)]
[TestCase("=++1", 1)]
[TestCase("=-+-+-1", -1)]
[TestCase("=2^---2", 0.25)]
public void MultipleUnaryOperators(string formula, double expectedResult)
{
var res = (double)XLWorkbook.EvaluateExpr(formula);
Assert.AreEqual(expectedResult, res, XLHelper.Epsilon);
}
[TestCase("RIGHT(\"2020\", 2) + 1", 21)]
[TestCase("LEFT(\"20.2020\", 6) + 1", 21.202)]
[TestCase("2 + (\"3\" & \"4\")", 36)]
[TestCase("2 + \"3\" & \"4\"", "54")]
[TestCase("\"7\" & \"4\"", "74")]
public void TestStringSubExpression(string formula, object expectedResult)
{
var actual = XLWorkbook.EvaluateExpr(formula);
Assert.AreEqual(expectedResult, actual);
}
}
}
@@ -0,0 +1,436 @@
using ClosedXML.Excel;
using NUnit.Framework;
using System;
using System.Globalization;
using System.Threading;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class InformationTests
{
[SetUp]
public void SetCultureInfo()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
}
#region IsBlank Tests
[Test]
public void IsBlank_MultipleAllEmpty_true()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
var actual = ws.Evaluate("=IsBlank(A1:A3)");
Assert.AreEqual(true, actual);
}
}
[Test]
public void IsBlank_MultipleAllFill_false()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "1";
ws.Cell("A2").Value = "1";
ws.Cell("A3").Value = "1";
var actual = ws.Evaluate("=IsBlank(A1:A3)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsBlank_MultipleMixedFill_false()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "1";
ws.Cell("A3").Value = "1";
var actual = ws.Evaluate("=IsBlank(A1:A3)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsBlank_Single_false()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = " ";
var actual = ws.Evaluate("=IsBlank(A1)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsBlank_Single_true()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
var actual = ws.Evaluate("=IsBlank(A1)");
Assert.AreEqual(true, actual);
}
}
#endregion IsBlank Tests
#region IsEven Tests
[Test]
public void IsEven_Single_False()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = 1;
ws.Cell("A2").Value = 1.2;
ws.Cell("A3").Value = 3;
var actual = ws.Evaluate("=IsEven(A1)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsEven(A2)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsEven(A3)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsEven_Single_True()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = 4;
ws.Cell("A2").Value = 0.2;
ws.Cell("A3").Value = 12.2;
var actual = ws.Evaluate("=IsEven(A1)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsEven(A2)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsEven(A3)");
Assert.AreEqual(true, actual);
}
}
#endregion IsEven Tests
#region IsLogical Tests
[Test]
public void IsLogical_Simpe_False()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = 123;
var actual = ws.Evaluate("=IsLogical(A1)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsLogical_Simple_True()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = true;
var actual = ws.Evaluate("=IsLogical(A1)");
Assert.AreEqual(true, actual);
}
}
#endregion IsLogical Tests
[Test]
public void IsNA()
{
object actual;
actual = XLWorkbook.EvaluateExpr("ISNA(#N/A)");
Assert.AreEqual(true, actual);
actual = XLWorkbook.EvaluateExpr("ISNA(#REF!)");
Assert.AreEqual(false, actual);
}
#region IsNotText Tests
[Test]
public void IsNotText_Simple_false()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "asd";
var actual = ws.Evaluate("=IsNonText(A1)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsNotText_Simple_true()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "123"; //Double Value
ws.Cell("A2").Value = DateTime.Now; //Date Value
ws.Cell("A3").Value = "12,235.5"; //Comma Formatting
ws.Cell("A4").Value = "$12,235.5"; //Currency Value
ws.Cell("A5").Value = true; //Bool Value
ws.Cell("A6").Value = "12%"; //Percentage Value
var actual = ws.Evaluate("=IsNonText(A1)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNonText(A2)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNonText(A3)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNonText(A4)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNonText(A5)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNonText(A6)");
Assert.AreEqual(true, actual);
}
}
#endregion IsNotText Tests
#region IsNumber Tests
[Test]
public void IsNumber_Simple_false()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "asd"; //String Value
ws.Cell("A2").Value = true; //Bool Value
var actual = ws.Evaluate("=IsNumber(A1)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsNumber(A2)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsNumber_Simple_true()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "123"; //Double Value
ws.Cell("A2").Value = DateTime.Now; //Date Value
ws.Cell("A3").Value = "12,235.5"; //Coma Formatting
ws.Cell("A4").Value = "$12,235.5"; //Currency Value
ws.Cell("A5").Value = "12%"; //Percentage Value
var actual = ws.Evaluate("=IsNumber(A1)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNumber(A2)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNumber(A3)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNumber(A4)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsNumber(A5)");
Assert.AreEqual(true, actual);
}
}
#endregion IsNumber Tests
#region IsOdd Test
[Test]
public void IsOdd_Simple_false()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = 4;
ws.Cell("A2").Value = 0.2;
ws.Cell("A3").Value = 12.2;
var actual = ws.Evaluate("=IsOdd(A1)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsOdd(A2)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsOdd(A3)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsOdd_Simple_true()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = 1;
ws.Cell("A2").Value = 1.2;
ws.Cell("A3").Value = 3;
var actual = ws.Evaluate("=IsOdd(A1)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsOdd(A2)");
Assert.AreEqual(true, actual);
actual = ws.Evaluate("=IsOdd(A3)");
Assert.AreEqual(true, actual);
}
}
#endregion IsOdd Test
[Test]
public void IsRef()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "123";
ws.Cell("B1").FormulaA1 = "ISREF(A1)";
ws.Cell("B2").FormulaA1 = "ISREF(5)";
ws.Cell("B3").FormulaA1 = "ISREF(YEAR(TODAY()))";
bool actual;
actual = ws.Cell("B1").GetValue<bool>();
Assert.AreEqual(true, actual);
actual = ws.Cell("B2").GetValue<bool>();
Assert.AreEqual(false, actual);
actual = ws.Cell("B3").GetValue<bool>();
Assert.AreEqual(false, actual);
}
}
#region IsText Tests
[Test]
public void IsText_Simple_false()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "123"; //Double Value
ws.Cell("A2").Value = DateTime.Now; //Date Value
ws.Cell("A3").Value = "12,235.5"; //Comma Formatting
ws.Cell("A4").Value = "$12,235.5"; //Currency Value
ws.Cell("A5").Value = true; //Bool Value
ws.Cell("A6").Value = "12%"; //Percentage Value
var actual = ws.Evaluate("=IsText(A1)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsText(A2)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsText(A3)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsText(A4)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsText(A5)");
Assert.AreEqual(false, actual);
actual = ws.Evaluate("=IsText(A6)");
Assert.AreEqual(false, actual);
}
}
[Test]
public void IsText_Simple_true()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "asd";
var actual = ws.Evaluate("=IsText(A1)");
Assert.AreEqual(true, actual);
}
}
#endregion IsText Tests
#region N Tests
[Test]
public void N_Date_SerialNumber()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
var testedDate = DateTime.Now;
ws.Cell("A1").Value = testedDate;
var actual = ws.Evaluate("=N(A1)");
Assert.AreEqual(testedDate.ToOADate(), actual);
}
}
[Test]
public void N_False_Zero()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = false;
var actual = ws.Evaluate("=N(A1)");
Assert.AreEqual(0, actual);
}
}
[Test]
public void N_Number_Number()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
var testedValue = 123;
ws.Cell("A1").Value = testedValue;
var actual = ws.Evaluate("=N(A1)");
Assert.AreEqual(testedValue, actual);
}
}
[Test]
public void N_String_Zero()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = "asd";
var actual = ws.Evaluate("=N(A1)");
Assert.AreEqual(0, actual);
}
}
[Test]
public void N_True_One()
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet");
ws.Cell("A1").Value = true;
var actual = ws.Evaluate("=N(A1)");
Assert.AreEqual(1, actual);
}
}
#endregion N Tests
}
}
@@ -0,0 +1,63 @@
using ClosedXML.Excel;
using NUnit.Framework;
using System;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class LogicalTests
{
[Test]
public void If_2_Params_true()
{
Object actual = XLWorkbook.EvaluateExpr(@"if(1 = 1, ""T"")");
Assert.AreEqual("T", actual);
}
[Test]
public void If_2_Params_false()
{
Object actual = XLWorkbook.EvaluateExpr(@"if(1 = 2, ""T"")");
Assert.AreEqual(false, actual);
}
[Test]
public void If_3_Params_true()
{
Object actual = XLWorkbook.EvaluateExpr(@"if(1 = 1, ""T"", ""F"")");
Assert.AreEqual("T", actual);
}
[Test]
public void If_3_Params_false()
{
Object actual = XLWorkbook.EvaluateExpr(@"if(1 = 2, ""T"", ""F"")");
Assert.AreEqual("F", actual);
}
[Test]
public void If_Comparing_Against_Empty_String()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"if(date(2016, 1, 1) = """", ""A"",""B"")");
Assert.AreEqual("B", actual);
actual = XLWorkbook.EvaluateExpr(@"if("""" = date(2016, 1, 1), ""A"",""B"")");
Assert.AreEqual("B", actual);
actual = XLWorkbook.EvaluateExpr(@"if("""" = 123, ""A"",""B"")");
Assert.AreEqual("B", actual);
actual = XLWorkbook.EvaluateExpr(@"if("""" = """", ""A"",""B"")");
Assert.AreEqual("A", actual);
}
[Test]
public void If_Case_Insensitivity()
{
Object actual;
actual = XLWorkbook.EvaluateExpr(@"IF(""text""=""TEXT"", 1, 2)");
Assert.AreEqual(1, actual);
}
}
}
@@ -0,0 +1,250 @@
// Keep this file CodeMaid organised and cleaned
using ClosedXML.Excel;
using ClosedXML.Excel.CalcEngine.Exceptions;
using NUnit.Framework;
using System;
using System.Linq;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class LookupTests
{
private XLWorkbook workbook;
#region Setup and teardown
[OneTimeTearDown]
public void Dispose()
{
workbook.Dispose();
}
[SetUp]
public void Init()
{
// Make sure tests run on a deterministic culture
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
workbook = SetupWorkbook();
}
private XLWorkbook SetupWorkbook()
{
var wb = new XLWorkbook();
var ws = wb.AddWorksheet("Data");
var data = new object[]
{
new {Id=1, OrderDate = DateTime.Parse("2015-01-06"), Region = "East", Rep = "Jones", Item = "Pencil", Units = 95, UnitCost = 1.99, Total = 189.05 },
new {Id=2, OrderDate = DateTime.Parse("2015-01-23"), Region = "Central", Rep = "Kivell", Item = "Binder", Units = 50, UnitCost = 19.99, Total = 999.5},
new {Id=3, OrderDate = DateTime.Parse("2015-02-09"), Region = "Central", Rep = "Jardine", Item = "Pencil", Units = 36, UnitCost = 4.99, Total = 179.64},
new {Id=4, OrderDate = DateTime.Parse("2015-02-26"), Region = "Central", Rep = "Gill", Item = "Pen", Units = 27, UnitCost = 19.99, Total = 539.73},
new {Id=5, OrderDate = DateTime.Parse("2015-03-15"), Region = "West", Rep = "Sorvino", Item = "Pencil", Units = 56, UnitCost = 2.99, Total = 167.44},
new {Id=6, OrderDate = DateTime.Parse("2015-04-01"), Region = "East", Rep = "Jones", Item = "Binder", Units = 60, UnitCost = 4.99, Total = 299.4},
new {Id=7, OrderDate = DateTime.Parse("2015-04-18"), Region = "Central", Rep = "Andrews", Item = "Pencil", Units = 75, UnitCost = 1.99, Total = 149.25},
new {Id=8, OrderDate = DateTime.Parse("2015-05-05"), Region = "Central", Rep = "Jardine", Item = "Pencil", Units = 90, UnitCost = 4.99, Total = 449.1},
new {Id=9, OrderDate = DateTime.Parse("2015-05-22"), Region = "West", Rep = "Thompson", Item = "Pencil", Units = 32, UnitCost = 1.99, Total = 63.68},
new {Id=10, OrderDate = DateTime.Parse("2015-06-08"), Region = "East", Rep = "Jones", Item = "Binder", Units = 60, UnitCost = 8.99, Total = 539.4},
new {Id=11, OrderDate = DateTime.Parse("2015-06-25"), Region = "Central", Rep = "Morgan", Item = "Pencil", Units = 90, UnitCost = 4.99, Total = 449.1},
new {Id=12, OrderDate = DateTime.Parse("2015-07-12"), Region = "East", Rep = "Howard", Item = "Binder", Units = 29, UnitCost = 1.99, Total = 57.71},
new {Id=13, OrderDate = DateTime.Parse("2015-07-29"), Region = "East", Rep = "Parent", Item = "Binder", Units = 81, UnitCost = 19.99, Total = 1619.19},
new {Id=14, OrderDate = DateTime.Parse("2015-08-15"), Region = "East", Rep = "Jones", Item = "Pencil", Units = 35, UnitCost = 4.99, Total = 174.65},
new {Id=15, OrderDate = DateTime.Parse("2015-09-01"), Region = "Central", Rep = "Smith", Item = "Desk", Units = 2, UnitCost = 125, Total = 250},
new {Id=16, OrderDate = DateTime.Parse("2015-09-18"), Region = "East", Rep = "Jones", Item = "Pen Set", Units = 16, UnitCost = 15.99, Total = 255.84},
new {Id=17, OrderDate = DateTime.Parse("2015-10-05"), Region = "Central", Rep = "Morgan", Item = "Binder", Units = 28, UnitCost = 8.99, Total = 251.72},
new {Id=18, OrderDate = DateTime.Parse("2015-10-22"), Region = "East", Rep = "Jones", Item = "Pen", Units = 64, UnitCost = 8.99, Total = 575.36},
new {Id=19, OrderDate = DateTime.Parse("2015-11-08"), Region = "East", Rep = "Parent", Item = "Pen", Units = 15, UnitCost = 19.99, Total = 299.85},
new {Id=20, OrderDate = DateTime.Parse("2015-11-25"), Region = "Central", Rep = "Kivell", Item = "Pen Set", Units = 96, UnitCost = 4.99, Total = 479.04},
new {Id=21, OrderDate = DateTime.Parse("2015-12-12"), Region = "Central", Rep = "Smith", Item = "Pencil", Units = 67, UnitCost = 1.29, Total = 86.43},
new {Id=22, OrderDate = DateTime.Parse("2015-12-29"), Region = "East", Rep = "Parent", Item = "Pen Set", Units = 74, UnitCost = 15.99, Total = 1183.26},
new {Id=23, OrderDate = DateTime.Parse("2016-01-15"), Region = "Central", Rep = "Gill", Item = "Binder", Units = 46, UnitCost = 8.99, Total = 413.54},
new {Id=24, OrderDate = DateTime.Parse("2016-02-01"), Region = "Central", Rep = "Smith", Item = "Binder", Units = 87, UnitCost = 15, Total = 1305},
new {Id=25, OrderDate = DateTime.Parse("2016-02-18"), Region = "East", Rep = "Jones", Item = "Binder", Units = 4, UnitCost = 4.99, Total = 19.96},
new {Id=26, OrderDate = DateTime.Parse("2016-03-07"), Region = "West", Rep = "Sorvino", Item = "Binder", Units = 7, UnitCost = 19.99, Total = 139.93},
new {Id=27, OrderDate = DateTime.Parse("2016-03-24"), Region = "Central", Rep = "Jardine", Item = "Pen Set", Units = 50, UnitCost = 4.99, Total = 249.5},
new {Id=28, OrderDate = DateTime.Parse("2016-04-10"), Region = "Central", Rep = "Andrews", Item = "Pencil", Units = 66, UnitCost = 1.99, Total = 131.34},
new {Id=29, OrderDate = DateTime.Parse("2016-04-27"), Region = "East", Rep = "Howard", Item = "Pen", Units = 96, UnitCost = 4.99, Total = 479.04},
new {Id=30, OrderDate = DateTime.Parse("2016-05-14"), Region = "Central", Rep = "Gill", Item = "Pencil", Units = 53, UnitCost = 1.29, Total = 68.37},
new {Id=31, OrderDate = DateTime.Parse("2016-05-31"), Region = "Central", Rep = "Gill", Item = "Binder", Units = 80, UnitCost = 8.99, Total = 719.2},
new {Id=32, OrderDate = DateTime.Parse("2016-06-17"), Region = "Central", Rep = "Kivell", Item = "Desk", Units = 5, UnitCost = 125, Total = 625},
new {Id=33, OrderDate = DateTime.Parse("2016-07-04"), Region = "East", Rep = "Jones", Item = "Pen Set", Units = 62, UnitCost = 4.99, Total = 309.38},
new {Id=34, OrderDate = DateTime.Parse("2016-07-21"), Region = "Central", Rep = "Morgan", Item = "Pen Set", Units = 55, UnitCost = 12.49, Total = 686.95},
new {Id=35, OrderDate = DateTime.Parse("2016-08-07"), Region = "Central", Rep = "Kivell", Item = "Pen Set", Units = 42, UnitCost = 23.95, Total = 1005.9},
new {Id=36, OrderDate = DateTime.Parse("2016-08-24"), Region = "West", Rep = "Sorvino", Item = "Desk", Units = 3, UnitCost = 275, Total = 825},
new {Id=37, OrderDate = DateTime.Parse("2016-09-10"), Region = "Central", Rep = "Gill", Item = "Pencil", Units = 7, UnitCost = 1.29, Total = 9.03},
new {Id=38, OrderDate = DateTime.Parse("2016-09-27"), Region = "West", Rep = "Sorvino", Item = "Pen", Units = 76, UnitCost = 1.99, Total = 151.24},
new {Id=39, OrderDate = DateTime.Parse("2016-10-14"), Region = "West", Rep = "Thompson", Item = "Binder", Units = 57, UnitCost = 19.99, Total = 1139.43},
new {Id=40, OrderDate = DateTime.Parse("2016-10-31"), Region = "Central", Rep = "Andrews", Item = "Pencil", Units = 14, UnitCost = 1.29, Total = 18.06},
new {Id=41, OrderDate = DateTime.Parse("2016-11-17"), Region = "Central", Rep = "Jardine", Item = "Binder", Units = 11, UnitCost = 4.99, Total = 54.89},
new {Id=42, OrderDate = DateTime.Parse("2016-12-04"), Region = "Central", Rep = "Jardine", Item = "Binder", Units = 94, UnitCost = 19.99, Total = 1879.06},
new {Id=43, OrderDate = DateTime.Parse("2016-12-21"), Region = "Central", Rep = "Andrews", Item = "Binder", Units = 28, UnitCost = 4.99, Total = 139.72}
};
ws.FirstCell()
.CellBelow()
.CellRight()
.InsertTable(data);
return wb;
}
#endregion Setup and teardown
[Test]
public void Hlookup()
{
// Range lookup false
var value = workbook.Evaluate(@"=HLOOKUP(""Total"",Data!$B$2:$I$71,4,FALSE)");
Assert.AreEqual(179.64, value);
}
[Test]
public void Hyperlink()
{
XLHyperlink hl;
hl = XLWorkbook.EvaluateExpr("HYPERLINK(\"http://github.com/ClosedXML/ClosedXML\")") as XLHyperlink;
Assert.IsNotNull(hl);
Assert.AreEqual("http://github.com/ClosedXML/ClosedXML", hl.ExternalAddress.ToString());
Assert.AreEqual(string.Empty, hl.Tooltip);
hl = XLWorkbook.EvaluateExpr("HYPERLINK(\"mailto:jsmith@github.com\", \"jsmith@github.com\")") as XLHyperlink;
Assert.IsNotNull(hl);
Assert.AreEqual("mailto:jsmith@github.com", hl.ExternalAddress.ToString());
Assert.AreEqual("jsmith@github.com", hl.Tooltip);
}
[Test]
public void Index()
{
var ws = workbook.Worksheets.First();
Assert.AreEqual("Kivell", ws.Evaluate(@"=INDEX(B2:J12, 3, 4)"));
// We don't support optional parameter fully here yet.
// Supposedly, if you omit e.g. the row number, then ROW() of the calling cell should be assumed
// Assert.AreEqual("Gill", ws.Evaluate(@"=INDEX(B2:J12, , 4)"));
Assert.AreEqual("Rep", ws.Evaluate(@"=INDEX(B2:I2, 4)"));
Assert.AreEqual(3, ws.Evaluate(@"=INDEX(B2:B20, 4)"));
Assert.AreEqual(3, ws.Evaluate(@"=INDEX(B2:B20, 4, 1)"));
Assert.AreEqual(3, ws.Evaluate(@"=INDEX(B2:B20, 4, )"));
Assert.AreEqual("Rep", ws.Evaluate(@"=INDEX(B2:J2, 1, 4)"));
Assert.AreEqual("Rep", ws.Evaluate(@"=INDEX(B2:J2, , 4)"));
}
[Test]
public void Index_Exceptions()
{
var ws = workbook.Worksheets.First();
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:I10, 20, 1)"));
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:I10, 1, 10)"));
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:I2, 10)"));
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:I2, 4, 1)"));
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:I2, 4, )"));
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:B10, 20)"));
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:B10, 20, )"));
Assert.Throws<CellReferenceException>(() => ws.Evaluate(@"INDEX(B2:B10, , 4)"));
}
[Test]
public void Match()
{
var ws = workbook.Worksheets.First();
Object value;
value = ws.Evaluate(@"=MATCH(""Rep"", B2:I2, 0)");
Assert.AreEqual(4, value);
value = ws.Evaluate(@"=MATCH(""Rep"", A2:Z2, 0)");
Assert.AreEqual(5, value);
value = ws.Evaluate(@"=MATCH(""REP"", B2:I2, 0)");
Assert.AreEqual(4, value);
value = ws.Evaluate(@"=MATCH(95, B3:I3, 0)");
Assert.AreEqual(6, value);
value = ws.Evaluate(@"=MATCH(DATE(2015,1,6), B3:I3, 0)");
Assert.AreEqual(2, value);
value = ws.Evaluate(@"=MATCH(1.99, 3:3, 0)");
Assert.AreEqual(8, value);
value = ws.Evaluate(@"=MATCH(43, B:B, 0)");
Assert.AreEqual(45, value);
value = ws.Evaluate(@"=MATCH(""cENtraL"", D3:D45, 0)");
Assert.AreEqual(2, value);
value = ws.Evaluate(@"=MATCH(4.99, H:H, 0)");
Assert.AreEqual(5, value);
value = ws.Evaluate(@"=MATCH(""Rapture"", B2:I2, 1)");
Assert.AreEqual(2, value);
value = ws.Evaluate(@"=MATCH(22.5, B3:B45, 1)");
Assert.AreEqual(22, value);
value = ws.Evaluate(@"=MATCH(""Rep"", B2:I2)");
Assert.AreEqual(4, value);
value = ws.Evaluate(@"=MATCH(""Rep"", B2:I2, 1)");
Assert.AreEqual(4, value);
value = ws.Evaluate(@"=MATCH(40, G3:G6, -1)");
Assert.AreEqual(2, value);
}
[Test]
public void Match_Exceptions()
{
var ws = workbook.Worksheets.First();
Assert.Throws<CellValueException>(() => ws.Evaluate(@"=MATCH(""Rep"", B2:I5)"));
Assert.Throws<NoValueAvailableException>(() => ws.Evaluate(@"=MATCH(""Dummy"", B2:I2, 0)"));
Assert.Throws<NoValueAvailableException>(() => ws.Evaluate(@"=MATCH(4.5,B3:B45,-1)"));
}
[Test]
public void Vlookup()
{
// Range lookup false
var value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,3,FALSE)");
Assert.AreEqual("Central", value);
value = workbook.Evaluate("=VLOOKUP(DATE(2015,5,22),Data!C:I,7,FALSE)");
Assert.AreEqual(63.68, value);
value = workbook.Evaluate(@"=VLOOKUP(""Central"",Data!D:E,2,FALSE)");
Assert.AreEqual("Kivell", value);
// Case insensitive lookup
value = workbook.Evaluate(@"=VLOOKUP(""central"",Data!D:E,2,FALSE)");
Assert.AreEqual("Kivell", value);
// Range lookup true
value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8,TRUE)");
Assert.AreEqual(179.64, value);
value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8)");
Assert.AreEqual(179.64, value);
value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8,)");
Assert.AreEqual(179.64, value);
value = workbook.Evaluate("=VLOOKUP(14.5,Data!$B$2:$I$71,8,TRUE)");
Assert.AreEqual(174.65, value);
value = workbook.Evaluate("=VLOOKUP(50,Data!$B$2:$I$71,8,TRUE)");
Assert.AreEqual(139.72, value);
}
[Test]
public void Vlookup_Exceptions()
{
Assert.Throws<NoValueAvailableException>(() => workbook.Evaluate(@"=VLOOKUP("""",Data!$B$2:$I$71,3,FALSE)"));
Assert.Throws<NoValueAvailableException>(() => workbook.Evaluate(@"=VLOOKUP(50,Data!$B$2:$I$71,3,FALSE)"));
Assert.Throws<NoValueAvailableException>(() => workbook.Evaluate(@"=VLOOKUP(-1,Data!$B$2:$I$71,2,TRUE)"));
Assert.Throws<CellReferenceException>(() => workbook.Evaluate(@"=VLOOKUP(20,Data!$B$2:$I$71,9,FALSE)"));
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,86 @@
using ClosedXML.Excel;
using NUnit.Framework;
using System.IO;
using System.Linq;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class PrecedentCellsTests
{
[Test]
public void GetPrecedentRangesPreventsDuplication()
{
using (var ms = new MemoryStream())
{
using (XLWorkbook wb = new XLWorkbook())
{
var sheet1 = wb.AddWorksheet("Sheet1") as XLWorksheet;
var sheet2 = wb.AddWorksheet("Sheet2");
var formula = "=MAX(A2:E2)/COUNTBLANK(A2:E2)*MAX(B1:C3)+SUM(Sheet2!B1:C3)+SUM($A$2:$E$2)+A2+B$2+$C$2";
var ranges = sheet1.CalcEngine.GetPrecedentRanges(formula);
Assert.AreEqual(6, ranges.Count());
Assert.IsTrue(ranges.Any(r => r.RangeAddress.Worksheet.Name == "Sheet1" && r.RangeAddress.ToString() == "A2:E2"));
Assert.IsTrue(ranges.Any(r => r.RangeAddress.Worksheet.Name == "Sheet1" && r.RangeAddress.ToString() == "B1:C3"));
Assert.IsTrue(ranges.Any(r => r.RangeAddress.Worksheet.Name == "Sheet2" && r.RangeAddress.ToString() == "B1:C3"));
Assert.IsTrue(ranges.Any(r => r.RangeAddress.Worksheet.Name == "Sheet1" && r.RangeAddress.ToString() == "A2:A2"));
Assert.IsTrue(ranges.Any(r => r.RangeAddress.Worksheet.Name == "Sheet1" && r.RangeAddress.ToString() == "B$2:B$2"));
Assert.IsTrue(ranges.Any(r => r.RangeAddress.Worksheet.Name == "Sheet1" && r.RangeAddress.ToString() == "$C$2:$C$2"));
}
}
}
[Test]
public void GetPrecedentRangesDealsWithNamedRanges()
{
using (var ms = new MemoryStream())
{
using (XLWorkbook wb = new XLWorkbook())
{
var sheet1 = wb.AddWorksheet("Sheet1") as XLWorksheet;
sheet1.NamedRanges.Add("NAMED_RANGE", sheet1.Range("A2:B3"));
var formula = "=SUM(NAMED_RANGE)";
var ranges = sheet1.CalcEngine.GetPrecedentRanges(formula);
Assert.AreEqual(1, ranges.Count());
Assert.AreEqual("$A$2:$B$3", ranges.First().RangeAddress.ToString());
}
}
}
[Test]
public void GetPrecedentCells()
{
using (var ms = new MemoryStream())
{
using (XLWorkbook wb = new XLWorkbook())
{
var sheet1 = wb.AddWorksheet("Sheet1") as XLWorksheet;
var sheet2 = wb.AddWorksheet("Sheet2");
var formula = "=MAX(A2:E2)/COUNTBLANK(A2:E2)*MAX(B1:C3)+SUM(Sheet2!B1:C3)+SUM($A$2:$E$2)+A2+B$2+$C$2";
var expectedAtSheet1 = new string[]
{ "A2", "B2", "C2", "D2", "E2", "B1", "C1", "B3", "C3" };
var expectedAtSheet2 = new string[]
{ "B1", "C1", "B2", "C2", "B3", "C3" };
var cells = sheet1.CalcEngine.GetPrecedentCells(formula);
Assert.AreEqual(15, cells.Count());
foreach (var address in expectedAtSheet1)
{
Assert.IsTrue(cells.Any(cell => cell.Address.Worksheet.Name == sheet1.Name && cell.Address.ToString() == address),
string.Format("Address {0}!{1} is not presented", sheet1.Name, address));
}
foreach (var address in expectedAtSheet2)
{
Assert.IsTrue(cells.Any(cell => cell.Address.Worksheet.Name == sheet2.Name && cell.Address.ToString() == address),
string.Format("Address {0}!{1} is not presented", sheet2.Name, address));
}
}
}
}
}
}
@@ -0,0 +1,457 @@
// Keep this file CodeMaid organised and cleaned
using ClosedXML.Excel;
using ClosedXML.Excel.CalcEngine;
using ClosedXML.Excel.CalcEngine.Exceptions;
using NUnit.Framework;
using System;
using System.Linq;
namespace ClosedXML_Tests.Excel.CalcEngine
{
[TestFixture]
public class StatisticalTests
{
private double tolerance = 1e-6;
private XLWorkbook workbook;
[Test]
public void Average()
{
double value;
value = workbook.Evaluate("AVERAGE(-27.5,93.93,64.51,-70.56)").CastTo<double>();
Assert.AreEqual(15.095, value, tolerance);
var ws = workbook.Worksheets.First();
value = ws.Evaluate("AVERAGE(G3:G45)").CastTo<double>();
Assert.AreEqual(49.3255814, value, tolerance);
Assert.That(() => ws.Evaluate("AVERAGE(D3:D45)"), Throws.TypeOf<ApplicationException>());
}
[Test]
public void Count()
{
var ws = workbook.Worksheets.First();
int value;
value = ws.Evaluate(@"=COUNT(D3:D45)").CastTo<int>();
Assert.AreEqual(0, value);
value = ws.Evaluate(@"=COUNT(G3:G45)").CastTo<int>();
Assert.AreEqual(43, value);
value = ws.Evaluate(@"=COUNT(G:G)").CastTo<int>();
Assert.AreEqual(43, value);
value = workbook.Evaluate(@"=COUNT(Data!G:G)").CastTo<int>();
Assert.AreEqual(43, value);
}
[Test]
public void CountA()
{
var ws = workbook.Worksheets.First();
int value;
value = ws.Evaluate(@"=COUNTA(D3:D45)").CastTo<int>();
Assert.AreEqual(43, value);
value = ws.Evaluate(@"=COUNTA(G3:G45)").CastTo<int>();
Assert.AreEqual(43, value);
value = ws.Evaluate(@"=COUNTA(G:G)").CastTo<int>();
Assert.AreEqual(44, value);
value = workbook.Evaluate(@"=COUNTA(Data!G:G)").CastTo<int>();
Assert.AreEqual(44, value);
}
[Test]
public void CountBlank()
{
var ws = workbook.Worksheets.First();
int value;
value = ws.Evaluate(@"=COUNTBLANK(B:B)").CastTo<int>();
Assert.AreEqual(1048532, value);
value = ws.Evaluate(@"=COUNTBLANK(D43:D49)").CastTo<int>();
Assert.AreEqual(4, value);
value = ws.Evaluate(@"=COUNTBLANK(E3:E45)").CastTo<int>();
Assert.AreEqual(0, value);
value = ws.Evaluate(@"=COUNTBLANK(A1)").CastTo<int>();
Assert.AreEqual(1, value);
Assert.Throws<NoValueAvailableException>(() => workbook.Evaluate(@"=COUNTBLANK(E3:E45)"));
Assert.Throws<ExpressionParseException>(() => ws.Evaluate(@"=COUNTBLANK()"));
Assert.Throws<ExpressionParseException>(() => ws.Evaluate(@"=COUNTBLANK(A3:A45,E3:E45)"));
}
[Test]
public void CountIf()
{
var ws = workbook.Worksheets.First();
int value;
value = ws.Evaluate(@"=COUNTIF(D3:D45,""Central"")").CastTo<int>();
Assert.AreEqual(24, value);
value = ws.Evaluate(@"=COUNTIF(D:D,""Central"")").CastTo<int>();
Assert.AreEqual(24, value);
value = workbook.Evaluate(@"=COUNTIF(Data!D:D,""Central"")").CastTo<int>();
Assert.AreEqual(24, value);
}
[TestCase(@"=COUNTIF(Data!E:E, ""J*"")", 13)]
[TestCase(@"=COUNTIF(Data!E:E, ""*i*"")", 21)]
[TestCase(@"=COUNTIF(Data!E:E, ""*in*"")", 9)]
[TestCase(@"=COUNTIF(Data!E:E, ""*i*l"")", 9)]
[TestCase(@"=COUNTIF(Data!E:E, ""*i?e*"")", 9)]
[TestCase(@"=COUNTIF(Data!E:E, ""*o??s*"")", 10)]
[TestCase(@"=COUNTIF(Data!X1:X1000, """")", 1000)]
[TestCase(@"=COUNTIF(Data!E1:E44, """")", 1)]
public void CountIf_ConditionWithWildcards(string formula, int expectedResult)
{
var ws = workbook.Worksheets.First();
int value = ws.Evaluate(formula).CastTo<int>();
Assert.AreEqual(expectedResult, value);
}
[TestCase(@"=COUNTIF(A1:A10, 1)", 1)]
[TestCase(@"=COUNTIF(A1:A10, 2.0)", 1)]
[TestCase(@"=COUNTIF(A1:A10, ""3"")", 2)]
[TestCase(@"=COUNTIF(A1:A10, 3)", 2)]
[TestCase(@"=COUNTIF(A1:A10, 43831)", 1)]
[TestCase(@"=COUNTIF(A1:A10, DATE(2020, 1, 1))", 1)]
[TestCase(@"=COUNTIF(A1:A10, TRUE)", 1)]
public void CountIf_MixedData(string formula, int expected)
{
// We follow to Excel's convention.
// Excel treats 1 and TRUE as unequal, but 3 and "3" as equal
// LibreOffice Calc handles some SUMIF and COUNTIF differently, e.g. it treats 1 and TRUE as equal, but 3 and "3" differently
var ws = workbook.Worksheet("MixedData");
Assert.AreEqual(expected, ws.Evaluate(formula));
}
[TestCase("x", @"=COUNTIF(A1:A1, ""?"")", 1)]
[TestCase("x", @"=COUNTIF(A1:A1, ""~?"")", 0)]
[TestCase("?", @"=COUNTIF(A1:A1, ""~?"")", 1)]
[TestCase("~?", @"=COUNTIF(A1:A1, ""~?"")", 0)]
[TestCase("~?", @"=COUNTIF(A1:A1, ""~~~?"")", 1)]
[TestCase("?", @"=COUNTIF(A1:A1, ""~~?"")", 0)]
[TestCase("~?", @"=COUNTIF(A1:A1, ""~~?"")", 1)]
[TestCase("~x", @"=COUNTIF(A1:A1, ""~~?"")", 1)]
[TestCase("*", @"=COUNTIF(A1:A1, ""~*"")", 1)]
[TestCase("~*", @"=COUNTIF(A1:A1, ""~*"")", 0)]
[TestCase("~*", @"=COUNTIF(A1:A1, ""~~~*"")", 1)]
[TestCase("*", @"=COUNTIF(A1:A1, ""~~*"")", 0)]
[TestCase("~*", @"=COUNTIF(A1:A1, ""~~*"")", 1)]
[TestCase("~x", @"=COUNTIF(A1:A1, ""~~*"")", 1)]
[TestCase("~xyz", @"=COUNTIF(A1:A1, ""~~*"")", 1)]
public void CountIf_MoreWildcards(string cellContent, string formula, int expectedResult)
{
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
ws.Cell(1, 1).Value = cellContent;
Assert.AreEqual(expectedResult, (double)ws.Evaluate(formula));
}
}
[TestCase("=COUNTIFS(B1:D1, \"=Yes\")", 1)]
[TestCase("=COUNTIFS(B1:B4, \"=Yes\", C1:C4, \"=Yes\")", 2)]
[TestCase("= COUNTIFS(B4:D4, \"=Yes\", B2:D2, \"=Yes\")", 1)]
public void CountIfs_ReferenceExample1FromExcelDocumentations(
string formula,
int expectedOutcome)
{
using (var wb = new XLWorkbook())
{
wb.ReferenceStyle = XLReferenceStyle.A1;
var ws = wb.AddWorksheet("Sheet1");
ws.Cell(1, 1).Value = "Davidoski";
ws.Cell(1, 2).Value = "Yes";
ws.Cell(1, 3).Value = "No";
ws.Cell(1, 4).Value = "No";
ws.Cell(2, 1).Value = "Burke";
ws.Cell(2, 2).Value = "Yes";
ws.Cell(2, 3).Value = "Yes";
ws.Cell(2, 4).Value = "No";
ws.Cell(3, 1).Value = "Sundaram";
ws.Cell(3, 2).Value = "Yes";
ws.Cell(3, 3).Value = "Yes";
ws.Cell(3, 4).Value = "Yes";
ws.Cell(4, 1).Value = "Levitan";
ws.Cell(4, 2).Value = "No";
ws.Cell(4, 3).Value = "Yes";
ws.Cell(4, 4).Value = "Yes";
Assert.AreEqual(expectedOutcome, ws.Evaluate(formula));
}
}
[Test]
public void CountIfs_SingleCondition()
{
var ws = workbook.Worksheets.First();
int value;
value = ws.Evaluate(@"=COUNTIFS(D3:D45,""Central"")").CastTo<int>();
Assert.AreEqual(24, value);
value = ws.Evaluate(@"=COUNTIFS(D:D,""Central"")").CastTo<int>();
Assert.AreEqual(24, value);
value = workbook.Evaluate(@"=COUNTIFS(Data!D:D,""Central"")").CastTo<int>();
Assert.AreEqual(24, value);
}
[TestCase(@"=COUNTIFS(Data!E:E, ""J*"")", 13)]
[TestCase(@"=COUNTIFS(Data!E:E, ""*i*"")", 21)]
[TestCase(@"=COUNTIFS(Data!E:E, ""*in*"")", 9)]
[TestCase(@"=COUNTIFS(Data!E:E, ""*i*l"")", 9)]
[TestCase(@"=COUNTIFS(Data!E:E, ""*i?e*"")", 9)]
[TestCase(@"=COUNTIFS(Data!E:E, ""*o??s*"")", 10)]
[TestCase(@"=COUNTIFS(Data!X1:X1000, """")", 1000)]
[TestCase(@"=COUNTIFS(Data!E1:E44, """")", 1)]
public void CountIfs_SingleConditionWithWildcards(string formula, int expectedResult)
{
var ws = workbook.Worksheets.First();
int value = ws.Evaluate(formula).CastTo<int>();
Assert.AreEqual(expectedResult, value);
}
[OneTimeTearDown]
public void Dispose()
{
workbook.Dispose();
}
[SetUp]
public void Init()
{
// Make sure tests run on a deterministic culture
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
workbook = SetupWorkbook();
}
[Test]
public void Max()
{
var ws = workbook.Worksheets.First();
int value;
value = ws.Evaluate(@"=MAX(D3:D45)").CastTo<int>();
Assert.AreEqual(0, value);
value = ws.Evaluate(@"=MAX(G3:G45)").CastTo<int>();
Assert.AreEqual(96, value);
value = ws.Evaluate(@"=MAX(G:G)").CastTo<int>();
Assert.AreEqual(96, value);
value = workbook.Evaluate(@"=MAX(Data!G:G)").CastTo<int>();
Assert.AreEqual(96, value);
}
[Test]
public void Min()
{
var ws = workbook.Worksheets.First();
int value;
value = ws.Evaluate(@"=MIN(D3:D45)").CastTo<int>();
Assert.AreEqual(0, value);
value = ws.Evaluate(@"=MIN(G3:G45)").CastTo<int>();
Assert.AreEqual(2, value);
value = ws.Evaluate(@"=MIN(G:G)").CastTo<int>();
Assert.AreEqual(2, value);
value = workbook.Evaluate(@"=MIN(Data!G:G)").CastTo<int>();
Assert.AreEqual(2, value);
}
[Test]
public void StDev()
{
var ws = workbook.Worksheets.First();
double value;
Assert.That(() => ws.Evaluate(@"=STDEV(D3:D45)"), Throws.TypeOf<ApplicationException>());
value = ws.Evaluate(@"=STDEV(H3:H45)").CastTo<double>();
Assert.AreEqual(47.34511769, value, tolerance);
value = ws.Evaluate(@"=STDEV(H:H)").CastTo<double>();
Assert.AreEqual(47.34511769, value, tolerance);
value = workbook.Evaluate(@"=STDEV(Data!H:H)").CastTo<double>();
Assert.AreEqual(47.34511769, value, tolerance);
}
[Test]
public void StDevP()
{
var ws = workbook.Worksheets.First();
double value;
Assert.That(() => ws.Evaluate(@"=STDEVP(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=STDEVP(H3:H45)").CastTo<double>();
Assert.AreEqual(46.79135458, value, tolerance);
value = ws.Evaluate(@"=STDEVP(H:H)").CastTo<double>();
Assert.AreEqual(46.79135458, value, tolerance);
value = workbook.Evaluate(@"=STDEVP(Data!H:H)").CastTo<double>();
Assert.AreEqual(46.79135458, value, tolerance);
}
[TestCase(@"=SUMIF(A1:A10, 1, A1:A10)", 1)]
[TestCase(@"=SUMIF(A1:A10, 2.0, A1:A10)", 2)]
[TestCase(@"=SUMIF(A1:A10, 3, A1:A10)", 3)]
[TestCase(@"=SUMIF(A1:A10, ""3"", A1:A10)", 3)]
[TestCase(@"=SUMIF(A1:A10, 43831, A1:A10)", 43831)]
[TestCase(@"=SUMIF(A1:A10, DATE(2020, 1, 1), A1:A10)", 43831)]
[TestCase(@"=SUMIF(A1:A10, TRUE, A1:A10)", 0)]
public void SumIf_MixedData(string formula, double expected)
{
// We follow to Excel's convention.
// Excel treats 1 and TRUE as unequal, but 3 and "3" as equal
// LibreOffice Calc handles some SUMIF and COUNTIF differently, e.g. it treats 1 and TRUE as equal, but 3 and "3" differently
var ws = workbook.Worksheet("MixedData");
Assert.AreEqual(expected, ws.Evaluate(formula));
}
[Test]
[TestCase("COUNT(G:I,G:G,H:I)", 258d, Description = "COUNT overlapping columns")]
[TestCase("COUNT(6:8,6:6,7:8)", 30d, Description = "COUNT overlapping rows")]
[TestCase("COUNTBLANK(H:J)", 3145640d, Description = "COUNTBLANK columns")]
[TestCase("COUNTBLANK(7:9)", 49128d, Description = "COUNTBLANK rows")]
[TestCase("COUNT(1:1048576)", 216d, Description = "COUNT worksheet")]
[TestCase("COUNTBLANK(1:1048576)", 17179868831d, Description = "COUNTBLANK worksheet")]
[TestCase("SUM(H:J)", 20501.15d, Description = "SUM columns")]
[TestCase("SUM(4:5)", 85366.12d, Description = "SUM rows")]
[TestCase("SUMIF(G:G,50,H:H)", 24.98d, Description = "SUMIF columns")]
[TestCase("SUMIF(G23:G52,\"\",H3:H32)", 53.24d, Description = "SUMIF ranges")]
[TestCase("SUMIFS(H:H,G:G,50,I:I,\">900\")", 19.99d, Description = "SUMIFS columns")]
public void TallySkipsEmptyCells(string formulaA1, double expectedResult)
{
using (var wb = SetupWorkbook())
{
var ws = wb.Worksheets.First();
//Let's pre-initialize cells we need so they didn't affect the result
ws.Range("A1:J45").Style.Fill.BackgroundColor = XLColor.Amber;
ws.Cell("ZZ1000").Value = 1;
int initialCount = (ws as XLWorksheet).Internals.CellsCollection.Count;
var actualResult = (double)ws.Evaluate(formulaA1);
int cellsCount = (ws as XLWorksheet).Internals.CellsCollection.Count;
Assert.AreEqual(expectedResult, actualResult, tolerance);
Assert.AreEqual(initialCount, cellsCount);
}
}
[Test]
public void Var()
{
var ws = workbook.Worksheets.First();
double value;
Assert.That(() => ws.Evaluate(@"=VAR(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=VAR(H3:H45)").CastTo<double>();
Assert.AreEqual(2241.560169, value, tolerance);
value = ws.Evaluate(@"=VAR(H:H)").CastTo<double>();
Assert.AreEqual(2241.560169, value, tolerance);
value = workbook.Evaluate(@"=VAR(Data!H:H)").CastTo<double>();
Assert.AreEqual(2241.560169, value, tolerance);
}
[Test]
public void VarP()
{
var ws = workbook.Worksheets.First();
double value;
Assert.That(() => ws.Evaluate(@"=VARP(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=VARP(H3:H45)").CastTo<double>();
Assert.AreEqual(2189.430863, value, tolerance);
value = ws.Evaluate(@"=VARP(H:H)").CastTo<double>();
Assert.AreEqual(2189.430863, value, tolerance);
value = workbook.Evaluate(@"=VARP(Data!H:H)").CastTo<double>();
Assert.AreEqual(2189.430863, value, tolerance);
}
private XLWorkbook SetupWorkbook()
{
var wb = new XLWorkbook();
var ws1 = wb.AddWorksheet("Data");
var data = new object[]
{
new {Id=1, OrderDate = DateTime.Parse("2015-01-06"), Region = "East", Rep = "Jones", Item = "Pencil", Units = 95, UnitCost = 1.99, Total = 189.05 },
new {Id=2, OrderDate = DateTime.Parse("2015-01-23"), Region = "Central", Rep = "Kivell", Item = "Binder", Units = 50, UnitCost = 19.99, Total = 999.5},
new {Id=3, OrderDate = DateTime.Parse("2015-02-09"), Region = "Central", Rep = "Jardine", Item = "Pencil", Units = 36, UnitCost = 4.99, Total = 179.64},
new {Id=4, OrderDate = DateTime.Parse("2015-02-26"), Region = "Central", Rep = "Gill", Item = "Pen", Units = 27, UnitCost = 19.99, Total = 539.73},
new {Id=5, OrderDate = DateTime.Parse("2015-03-15"), Region = "West", Rep = "Sorvino", Item = "Pencil", Units = 56, UnitCost = 2.99, Total = 167.44},
new {Id=6, OrderDate = DateTime.Parse("2015-04-01"), Region = "East", Rep = "Jones", Item = "Binder", Units = 60, UnitCost = 4.99, Total = 299.4},
new {Id=7, OrderDate = DateTime.Parse("2015-04-18"), Region = "Central", Rep = "Andrews", Item = "Pencil", Units = 75, UnitCost = 1.99, Total = 149.25},
new {Id=8, OrderDate = DateTime.Parse("2015-05-05"), Region = "Central", Rep = "Jardine", Item = "Pencil", Units = 90, UnitCost = 4.99, Total = 449.1},
new {Id=9, OrderDate = DateTime.Parse("2015-05-22"), Region = "West", Rep = "Thompson", Item = "Pencil", Units = 32, UnitCost = 1.99, Total = 63.68},
new {Id=10, OrderDate = DateTime.Parse("2015-06-08"), Region = "East", Rep = "Jones", Item = "Binder", Units = 60, UnitCost = 8.99, Total = 539.4},
new {Id=11, OrderDate = DateTime.Parse("2015-06-25"), Region = "Central", Rep = "Morgan", Item = "Pencil", Units = 90, UnitCost = 4.99, Total = 449.1},
new {Id=12, OrderDate = DateTime.Parse("2015-07-12"), Region = "East", Rep = "Howard", Item = "Binder", Units = 29, UnitCost = 1.99, Total = 57.71},
new {Id=13, OrderDate = DateTime.Parse("2015-07-29"), Region = "East", Rep = "Parent", Item = "Binder", Units = 81, UnitCost = 19.99, Total = 1619.19},
new {Id=14, OrderDate = DateTime.Parse("2015-08-15"), Region = "East", Rep = "Jones", Item = "Pencil", Units = 35, UnitCost = 4.99, Total = 174.65},
new {Id=15, OrderDate = DateTime.Parse("2015-09-01"), Region = "Central", Rep = "Smith", Item = "Desk", Units = 2, UnitCost = 125, Total = 250},
new {Id=16, OrderDate = DateTime.Parse("2015-09-18"), Region = "East", Rep = "Jones", Item = "Pen Set", Units = 16, UnitCost = 15.99, Total = 255.84},
new {Id=17, OrderDate = DateTime.Parse("2015-10-05"), Region = "Central", Rep = "Morgan", Item = "Binder", Units = 28, UnitCost = 8.99, Total = 251.72},
new {Id=18, OrderDate = DateTime.Parse("2015-10-22"), Region = "East", Rep = "Jones", Item = "Pen", Units = 64, UnitCost = 8.99, Total = 575.36},
new {Id=19, OrderDate = DateTime.Parse("2015-11-08"), Region = "East", Rep = "Parent", Item = "Pen", Units = 15, UnitCost = 19.99, Total = 299.85},
new {Id=20, OrderDate = DateTime.Parse("2015-11-25"), Region = "Central", Rep = "Kivell", Item = "Pen Set", Units = 96, UnitCost = 4.99, Total = 479.04},
new {Id=21, OrderDate = DateTime.Parse("2015-12-12"), Region = "Central", Rep = "Smith", Item = "Pencil", Units = 67, UnitCost = 1.29, Total = 86.43},
new {Id=22, OrderDate = DateTime.Parse("2015-12-29"), Region = "East", Rep = "Parent", Item = "Pen Set", Units = 74, UnitCost = 15.99, Total = 1183.26},
new {Id=23, OrderDate = DateTime.Parse("2016-01-15"), Region = "Central", Rep = "Gill", Item = "Binder", Units = 46, UnitCost = 8.99, Total = 413.54},
new {Id=24, OrderDate = DateTime.Parse("2016-02-01"), Region = "Central", Rep = "Smith", Item = "Binder", Units = 87, UnitCost = 15, Total = 1305},
new {Id=25, OrderDate = DateTime.Parse("2016-02-18"), Region = "East", Rep = "Jones", Item = "Binder", Units = 4, UnitCost = 4.99, Total = 19.96},
new {Id=26, OrderDate = DateTime.Parse("2016-03-07"), Region = "West", Rep = "Sorvino", Item = "Binder", Units = 7, UnitCost = 19.99, Total = 139.93},
new {Id=27, OrderDate = DateTime.Parse("2016-03-24"), Region = "Central", Rep = "Jardine", Item = "Pen Set", Units = 50, UnitCost = 4.99, Total = 249.5},
new {Id=28, OrderDate = DateTime.Parse("2016-04-10"), Region = "Central", Rep = "Andrews", Item = "Pencil", Units = 66, UnitCost = 1.99, Total = 131.34},
new {Id=29, OrderDate = DateTime.Parse("2016-04-27"), Region = "East", Rep = "Howard", Item = "Pen", Units = 96, UnitCost = 4.99, Total = 479.04},
new {Id=30, OrderDate = DateTime.Parse("2016-05-14"), Region = "Central", Rep = "Gill", Item = "Pencil", Units = 53, UnitCost = 1.29, Total = 68.37},
new {Id=31, OrderDate = DateTime.Parse("2016-05-31"), Region = "Central", Rep = "Gill", Item = "Binder", Units = 80, UnitCost = 8.99, Total = 719.2},
new {Id=32, OrderDate = DateTime.Parse("2016-06-17"), Region = "Central", Rep = "Kivell", Item = "Desk", Units = 5, UnitCost = 125, Total = 625},
new {Id=33, OrderDate = DateTime.Parse("2016-07-04"), Region = "East", Rep = "Jones", Item = "Pen Set", Units = 62, UnitCost = 4.99, Total = 309.38},
new {Id=34, OrderDate = DateTime.Parse("2016-07-21"), Region = "Central", Rep = "Morgan", Item = "Pen Set", Units = 55, UnitCost = 12.49, Total = 686.95},
new {Id=35, OrderDate = DateTime.Parse("2016-08-07"), Region = "Central", Rep = "Kivell", Item = "Pen Set", Units = 42, UnitCost = 23.95, Total = 1005.9},
new {Id=36, OrderDate = DateTime.Parse("2016-08-24"), Region = "West", Rep = "Sorvino", Item = "Desk", Units = 3, UnitCost = 275, Total = 825},
new {Id=37, OrderDate = DateTime.Parse("2016-09-10"), Region = "Central", Rep = "Gill", Item = "Pencil", Units = 7, UnitCost = 1.29, Total = 9.03},
new {Id=38, OrderDate = DateTime.Parse("2016-09-27"), Region = "West", Rep = "Sorvino", Item = "Pen", Units = 76, UnitCost = 1.99, Total = 151.24},
new {Id=39, OrderDate = DateTime.Parse("2016-10-14"), Region = "West", Rep = "Thompson", Item = "Binder", Units = 57, UnitCost = 19.99, Total = 1139.43},
new {Id=40, OrderDate = DateTime.Parse("2016-10-31"), Region = "Central", Rep = "Andrews", Item = "Pencil", Units = 14, UnitCost = 1.29, Total = 18.06},
new {Id=41, OrderDate = DateTime.Parse("2016-11-17"), Region = "Central", Rep = "Jardine", Item = "Binder", Units = 11, UnitCost = 4.99, Total = 54.89},
new {Id=42, OrderDate = DateTime.Parse("2016-12-04"), Region = "Central", Rep = "Jardine", Item = "Binder", Units = 94, UnitCost = 19.99, Total = 1879.06},
new {Id=43, OrderDate = DateTime.Parse("2016-12-21"), Region = "Central", Rep = "Andrews", Item = "Binder", Units = 28, UnitCost = 4.99, Total = 139.72}
};
ws1.FirstCell()
.CellBelow()
.CellRight()
.InsertTable(data, "Table1");
var ws2 = wb.AddWorksheet("MixedData");
ws2.FirstCell().InsertData(new object[] { 1, 2.0, "3", 3, new DateTime(2020, 1, 1), true, new TimeSpan(10, 5, 30, 10) });
return wb;
}
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,26 @@
using ClosedXML.Excel.CalcEngine.Functions;
using NUnit.Framework;
namespace ClosedXML_Tests.Excel.CalcEngine
{
/// <summary>
/// Summary description for UnitTest1
/// </summary>
[TestFixture]
public class XLMathTests
{
[Test]
public void IsEven()
{
Assert.IsTrue(XLMath.IsEven(2));
Assert.IsFalse(XLMath.IsEven(3));
}
[Test]
public void IsOdd()
{
Assert.IsTrue(XLMath.IsOdd(3));
Assert.IsFalse(XLMath.IsOdd(2));
}
}
}