diff --git a/main/SS/Formula/Atp/AnalysisToolPak.cs b/main/SS/Formula/Atp/AnalysisToolPak.cs index 9c61b310e..d2cc4b068 100644 --- a/main/SS/Formula/Atp/AnalysisToolPak.cs +++ b/main/SS/Formula/Atp/AnalysisToolPak.cs @@ -86,7 +86,7 @@ private static Dictionary CreateFunctionsMap() r(m, "BIN2OCT", null); r(m, "COMPLEX", Complex.Instance); r(m, "CONVERT", null); - r(m, "COUNTIFS", null); + r(m, "COUNTIFS", Countifs.instance); r(m, "COUPDAYBS", null); r(m, "COUPDAYS", null); r(m, "COUPDAYSNC", null); @@ -123,6 +123,7 @@ private static Dictionary CreateFunctionsMap() r(m, "HEX2DEC", Hex2Dec.instance); r(m, "HEX2OCT", null); r(m, "IFERROR", IfError.Instance); + r(m, "IFS", Ifs.Instance); r(m, "IMABS", null); r(m, "IMAGINARY", Imaginary.instance); r(m, "IMARGUMENT", null); @@ -145,7 +146,9 @@ private static Dictionary CreateFunctionsMap() r(m, "ISODD", ParityFunction.IS_ODD); r(m, "JIS", null); r(m, "LCM", null); + r(m, "MAXIFS", Maxifs.instance); r(m, "MDURATION", null); + r(m, "MINIFS", Minifs.instance); r(m, "MROUND", MRound.Instance); r(m, "MULTINOMIAL", null); r(m, "NETWORKDAYS", NetworkdaysFunction.instance); @@ -178,7 +181,6 @@ private static Dictionary CreateFunctionsMap() r(m, "YIELD", null); r(m, "YIELDDISC", null); r(m, "YIELDMAT", null); - r(m, "COUNTIFS", Countifs.instance); return m; } diff --git a/main/SS/Formula/Atp/Ifs.cs b/main/SS/Formula/Atp/Ifs.cs new file mode 100644 index 000000000..c66925707 --- /dev/null +++ b/main/SS/Formula/Atp/Ifs.cs @@ -0,0 +1,53 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for Additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ +using System; +using System.Collections.Generic; +using System.Text; +using NPOI.SS.Formula.Functions; +using NPOI.SS.Formula.Eval; + +namespace NPOI.SS.Formula.Atp +{ + class Ifs : FreeRefFunction + { + public static FreeRefFunction Instance = new Ifs(); + + private Ifs() + { + // enforce singleton + } + + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length % 2 != 0) + { + return ErrorEval.VALUE_INVALID; + } + + for (int i = 0; i < args.Length; i = i + 2) + { + BoolEval logicalTest = (BoolEval)args[i]; + if ( logicalTest.BooleanValue ) + { + return args[i + 1]; + } + } + + return ErrorEval.NA; + } + } +} \ No newline at end of file diff --git a/main/SS/Formula/Atp/Maxifs.cs b/main/SS/Formula/Atp/Maxifs.cs new file mode 100644 index 000000000..cee76702d --- /dev/null +++ b/main/SS/Formula/Atp/Maxifs.cs @@ -0,0 +1,70 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for Additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +namespace NPOI.SS.Formula.Atp +{ + using System; + using NPOI.SS.Formula; + using NPOI.SS.Formula.Functions; + using NPOI.SS.Formula.Eval; + + /** + * Implementation for the function MAXIFS + *

+ * Syntax: MAXIFS(data_range, criteria_range1, criteria1, [criteria_range2, criteria2]) + *

+ */ + + public class Maxifs : FreeRefFunction + { + public static FreeRefFunction instance = new Maxifs(); + + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length < 3 || args.Length % 2 == 0) + { + return ErrorEval.VALUE_INVALID; + } + + try + { + AreaEval dataRange = Sumifs.ConvertRangeArg(args[0]); + + // collect pairs of ranges and criteria + AreaEval[] ae = new AreaEval[(args.Length - 1) / 2]; + IMatchPredicate[] mp = new IMatchPredicate[ae.Length]; + for (int i = 1, k = 0; i < args.Length; i += 2, k++) + { + ae[k] = Sumifs.ConvertRangeArg(args[i]); + mp[k] = Countif.CreateCriteriaPredicate(args[i + 1], ec.RowIndex, ec.ColumnIndex); + } + + Sumifs.ValidateCriteriaRanges(ae, dataRange); + Sumifs.ValidateCriteria(mp); + + double result = Sumifs.CalcMatchingCells(ae, mp, dataRange, double.NaN, (init, current) => !current.HasValue ? init : double.IsNaN(init) ? current.Value : current.Value > init ? current.Value : init); + return new NumberEval(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + } + +} diff --git a/main/SS/Formula/Atp/MinIfs.cs b/main/SS/Formula/Atp/MinIfs.cs new file mode 100644 index 000000000..9ca3e72cc --- /dev/null +++ b/main/SS/Formula/Atp/MinIfs.cs @@ -0,0 +1,70 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for Additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + +namespace NPOI.SS.Formula.Atp +{ + using System; + using NPOI.SS.Formula; + using NPOI.SS.Formula.Functions; + using NPOI.SS.Formula.Eval; + + /** + * Implementation for the function MINIFS + *

+ * Syntax: MINIFS(min_range, criteria_range1, criteria1, [criteria_range2, criteria2]) + *

+ */ + + public class Minifs : FreeRefFunction + { + public static FreeRefFunction instance = new Minifs(); + + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if (args.Length < 3 || args.Length % 2 == 0) + { + return ErrorEval.VALUE_INVALID; + } + + try + { + AreaEval minRange = Sumifs.ConvertRangeArg(args[0]); + + // collect pairs of ranges and criteria + AreaEval[] ae = new AreaEval[(args.Length - 1) / 2]; + IMatchPredicate[] mp = new IMatchPredicate[ae.Length]; + for (int i = 1, k = 0; i < args.Length; i += 2, k++) + { + ae[k] = Sumifs.ConvertRangeArg(args[i]); + mp[k] = Countif.CreateCriteriaPredicate(args[i + 1], ec.RowIndex, ec.ColumnIndex); + } + + Sumifs.ValidateCriteriaRanges(ae, minRange); + Sumifs.ValidateCriteria(mp); + + double result = Sumifs.CalcMatchingCells(ae, mp, minRange, double.NaN, (init, current) => !current.HasValue ? init : double.IsNaN(init) ? current.Value : current.Value < init ? current.Value : init); + return new NumberEval(result); + } + catch (EvaluationException e) + { + return e.GetErrorEval(); + } + } + } + +} diff --git a/main/SS/Formula/Functions/Averageifs.cs b/main/SS/Formula/Functions/Averageifs.cs index c8fd631bc..434684af7 100644 --- a/main/SS/Formula/Functions/Averageifs.cs +++ b/main/SS/Formula/Functions/Averageifs.cs @@ -64,6 +64,7 @@ public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) } ValidateCriteriaRanges(ae, avgRange); + Sumifs.ValidateCriteria(mp); double result = GetAvgFromMatchingCells(ae, mp, avgRange); return new NumberEval(result); diff --git a/main/SS/Formula/Functions/Sumifs.cs b/main/SS/Formula/Functions/Sumifs.cs index 4ca8ef131..365d18476 100644 --- a/main/SS/Formula/Functions/Sumifs.cs +++ b/main/SS/Formula/Functions/Sumifs.cs @@ -69,7 +69,8 @@ public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) ValidateCriteriaRanges(ae, sumRange); ValidateCriteria(mp); - double result = SumMatchingCells(ae, mp, sumRange); + + double result = CalcMatchingCells(ae, mp, sumRange, 0.0, (init, current) => init + (current.HasValue ? current.Value : 0.0)); return new NumberEval(result); } catch (EvaluationException e) @@ -82,7 +83,7 @@ public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) * * @throws EvaluationException if there are criteria which resulted in Errors. */ - private void ValidateCriteria(IMatchPredicate[] criteria) + internal static void ValidateCriteria(IMatchPredicate[] criteria) { foreach (IMatchPredicate predicate in criteria) { @@ -100,7 +101,7 @@ private void ValidateCriteria(IMatchPredicate[] criteria) * * @throws EvaluationException if */ - private void ValidateCriteriaRanges(AreaEval[] criteriaRanges, AreaEval sumRange) + internal static void ValidateCriteriaRanges(AreaEval[] criteriaRanges, AreaEval sumRange) { foreach (AreaEval r in criteriaRanges) { @@ -120,12 +121,12 @@ private void ValidateCriteriaRanges(AreaEval[] criteriaRanges, AreaEval sumRange * * @return the computed value */ - private static double SumMatchingCells(AreaEval[] ranges, IMatchPredicate[] predicates, AreaEval aeSum) + internal static double CalcMatchingCells(AreaEval[] ranges, IMatchPredicate[] predicates, AreaEval aeSum, double initialValue, System.Func calc) { int height = aeSum.Height; int width = aeSum.Width; - double result = 0.0; + double result = initialValue; for (int r = 0; r < height; r++) { for (int c = 0; c < width; c++) @@ -147,15 +148,17 @@ private static double SumMatchingCells(AreaEval[] ranges, IMatchPredicate[] pred if (matches) { // sum only if all of the corresponding criteria specified are true for that cell. - result += Accumulate(aeSum, r, c); + result = calc(result, ReadValue(aeSum, r, c)); } } } return result; } - private static double Accumulate(AreaEval aeSum, int relRowIndex, - int relColIndex) + /** + * Reads the numeric values from the row/col of the specified area - other values return the indicated missing value. + */ + private static double? ReadValue(AreaEval aeSum, int relRowIndex, int relColIndex) { ValueEval addend = aeSum.GetRelativeValue(relRowIndex, relColIndex); @@ -164,10 +167,10 @@ private static double Accumulate(AreaEval aeSum, int relRowIndex, return ((NumberEval)addend).NumberValue; } // everything else (including string and boolean values) counts as zero - return 0.0; + return null; } - private static AreaEval ConvertRangeArg(ValueEval eval) + internal static AreaEval ConvertRangeArg(ValueEval eval) { if (eval is AreaEval) { diff --git a/testcases/main/SS/Formula/Atp/TestIfs.cs b/testcases/main/SS/Formula/Atp/TestIfs.cs new file mode 100644 index 000000000..982045bdd --- /dev/null +++ b/testcases/main/SS/Formula/Atp/TestIfs.cs @@ -0,0 +1,66 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for Additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using NPOI.SS.UserModel; +using NPOI.HSSF.UserModel; +using NPOI.SS.Util; + +namespace TestCases.SS.Formula.Atp +{ + [TestFixture] + public class TestIfs + { + /// + /// =IFS(A1="A", "Value for A" , A1="B", "Value for B") + /// + [Test] + public void TestEvaluate() + { + IWorkbook wb = new HSSFWorkbook(); + ISheet sh = wb.CreateSheet(); + IRow row1 = sh.CreateRow(0); + + // Create cells + row1.CreateCell(0, CellType.String); + + // Create references + CellReference a1Ref = new CellReference("A1"); + + // Set values + ICell cellA1 = sh.GetRow(a1Ref.Row).GetCell(a1Ref.Col); + + ICell cell1 = row1.CreateCell(1); + cell1.CellFormula = "IFS(A1=\"A\", \"Value for A\", A1=\"B\",\"Value for B\")"; + + IFormulaEvaluator evaluator = wb.GetCreationHelper().CreateFormulaEvaluator(); + + cellA1.SetCellValue("A"); + Assert.AreEqual(CellType.String, evaluator.Evaluate(cell1).CellType, "Checks that the cell is numeric"); + Assert.AreEqual("Value for A", evaluator.Evaluate(cell1).StringValue, "IFS should return 'Value for B'"); + + cellA1.SetCellValue("B"); + evaluator.ClearAllCachedResultValues(); + + Assert.AreEqual(CellType.String, evaluator.Evaluate(cell1).CellType, "Checks that the cell is numeric"); + Assert.AreEqual("Value for B", evaluator.Evaluate(cell1).StringValue, "IFS should return 'Value for B'"); + } + } +} diff --git a/testcases/main/SS/Formula/Atp/TestMaxIfs.cs b/testcases/main/SS/Formula/Atp/TestMaxIfs.cs new file mode 100644 index 000000000..d663b57ef --- /dev/null +++ b/testcases/main/SS/Formula/Atp/TestMaxIfs.cs @@ -0,0 +1,169 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +namespace TestCases.SS.Formula.Atp +{ + using NPOI.HSSF.UserModel; + using NPOI.SS.Formula; + using NPOI.SS.Formula.Eval; + using NPOI.SS.Formula.Atp; + using NUnit.Framework; + using TestCases.SS.Formula.Functions; + + /** + * Test cases for MAXIFS() + */ + [TestFixture] + public class TestMaxIfs + { + private static OperationEvaluationContext EC = new OperationEvaluationContext(null, null, 0, 1, 0, null); + + private static ValueEval InvokeMaxIfs(ValueEval[] args, OperationEvaluationContext ec) + { + return new Maxifs().Evaluate(args, EC); + } + + private static void ConfirmDouble(double expected, ValueEval actualEval) + { + if (!(actualEval is NumericValueEval)) + { + throw new AssertionException("Expected numeric result"); + } + NumericValueEval nve = (NumericValueEval)actualEval; + Assert.AreEqual(expected, nve.NumberValue, 0); + } + + private static void Confirm(double expectedResult, ValueEval[] args) + { + ConfirmDouble(expectedResult, InvokeMaxIfs(args, EC)); + } + + /** + * Example 1 from + * https://support.microsoft.com/en-us/office/maxifs-function-dfd611e6-da2c-488a-919b-9b6376b28883 + */ + [Test] + public void TestExample1() + { + // mimic test sample from https://support.microsoft.com/en-us/office/maxifs-function-dfd611e6-da2c-488a-919b-9b6376b28883 + ValueEval[] a2a7 = new ValueEval[] + { + new NumberEval(89), + new NumberEval(93), + new NumberEval(91), + new NumberEval(96), + new NumberEval(85), + new NumberEval(88) + }; + + ValueEval[] b2b7 = new ValueEval[] + { + new NumberEval(1), + new NumberEval(2), + new NumberEval(2), + new NumberEval(3), + new NumberEval(1), + new NumberEval(1) + }; + + // "=MAXIFS(A2:A7,B2:B7,1)" + ValueEval[] args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new NumberEval(1) + }; + Confirm(89.0, args); + + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1") + }; + Confirm(96.0, args); + + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1"), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval("<3") + }; + Confirm(93.0, args); + } + + /** + * Ensure that this works with non-numeric data within the processed values. + */ + [Test] + public void TestMinWithNonNumeric() + { + ValueEval[] a2a7 = new ValueEval[] + { + new NumberEval(-89), + new NumberEval(-93), + new NumberEval(-96), + new NumberEval(-85), + new StringEval("Test"), + new NumberEval(-88) + }; + + ValueEval[] b2b7 = new ValueEval[] + { + new NumberEval(1), + new NumberEval(2), + new NumberEval(2), + new NumberEval(3), + new NumberEval(1), + new NumberEval(1) + }; + + // "=MaxIFS(A2:A7, B2:B7, "1")" + ValueEval[] args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new NumberEval(1) + }; + Confirm(-88.00, args); + + // "=MaxIFS(A2:A7, B2:B7, ">1")" + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1") + }; + Confirm(-85.0, args); + + // "=MaxIFS(A2:A7, B2:B7, ">1", B2:B7, "<3")" + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1"), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval("<3") + }; + Confirm(-93.0, args); + } + } +} \ No newline at end of file diff --git a/testcases/main/SS/Formula/Atp/TestMinifs.cs b/testcases/main/SS/Formula/Atp/TestMinifs.cs new file mode 100644 index 000000000..d1166e04e --- /dev/null +++ b/testcases/main/SS/Formula/Atp/TestMinifs.cs @@ -0,0 +1,169 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +namespace TestCases.SS.Formula.Atp +{ + using NPOI.HSSF.UserModel; + using NPOI.SS.Formula; + using NPOI.SS.Formula.Eval; + using NPOI.SS.Formula.Atp; + using NUnit.Framework; + using TestCases.SS.Formula.Functions; + + /** + * Test cases for MINIFS() + */ + [TestFixture] + public class TestMinifs + { + private static OperationEvaluationContext EC = new OperationEvaluationContext(null, null, 0, 1, 0, null); + + private static ValueEval InvokeMinifs(ValueEval[] args, OperationEvaluationContext ec) + { + return new Minifs().Evaluate(args, EC); + } + + private static void ConfirmDouble(double expected, ValueEval actualEval) + { + if (!(actualEval is NumericValueEval)) + { + throw new AssertionException("Expected numeric result"); + } + NumericValueEval nve = (NumericValueEval)actualEval; + Assert.AreEqual(expected, nve.NumberValue, 0); + } + + private static void Confirm(double expectedResult, ValueEval[] args) + { + ConfirmDouble(expectedResult, InvokeMinifs(args, EC)); + } + + /** + * Example 1 from + * https://support.microsoft.com/en-us/office/minifs-function-6ca1ddaa-079b-4e74-80cc-72eef32e6599 + */ + [Test] + public void TestExample1() + { + // mimic test sample from https://support.microsoft.com/en-us/office/minifs-function-6ca1ddaa-079b-4e74-80cc-72eef32e6599 + ValueEval[] a2a7 = new ValueEval[] + { + new NumberEval(89), + new NumberEval(93), + new NumberEval(96), + new NumberEval(85), + new NumberEval(91), + new NumberEval(88) + }; + + ValueEval[] b2b7 = new ValueEval[] + { + new NumberEval(1), + new NumberEval(2), + new NumberEval(2), + new NumberEval(3), + new NumberEval(1), + new NumberEval(1) + }; + + // "=MinIFS(A2:A9, B2:B9, "=A*", C2:C9, 1)" + ValueEval[] args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new NumberEval(1) + }; + Confirm(88.0, args); + + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1") + }; + Confirm(85.0, args); + + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1"), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval("<3") + }; + Confirm(93.0, args); + } + + /** + * Ensure that this works with non-numeric data within the processed values. + */ + [Test] + public void TestMinWithNonNumeric() + { + ValueEval[] a2a7 = new ValueEval[] + { + new NumberEval(89), + new NumberEval(93), + new NumberEval(96), + new NumberEval(85), + new StringEval("Test"), + new NumberEval(88) + }; + + ValueEval[] b2b7 = new ValueEval[] + { + new NumberEval(1), + new NumberEval(2), + new NumberEval(2), + new NumberEval(3), + new NumberEval(1), + new NumberEval(1) + }; + + // "=MinIFS(A2:A7, B2:B7, "1")" + ValueEval[] args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new NumberEval(1) + }; + Confirm(88.0, args); + + // "=MinIFS(A2:A7, B2:B7, ">1")" + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1") + }; + Confirm(85.0, args); + + // "=MinIFS(A2:A7, B2:B7, ">1", B2:B7, "<3")" + args = new ValueEval[] + { + EvalFactory.CreateAreaEval("A2:A7", a2a7), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval(">1"), + EvalFactory.CreateAreaEval("B2:B7", b2b7), + new StringEval("<3") + }; + Confirm(93.0, args); + } + } +} \ No newline at end of file