You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2026/09/20 11:17:03 UTC
(poi) branch trunk updated: FormulaEvaluator: tests for hidden rows (#1314)
This is an automated email from the ASF dual-hosted git repository.
pjfanning pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git
The following commit(s) were added to refs/heads/trunk by this push:
new 7bb2678b97 FormulaEvaluator: tests for hidden rows (#1314)
7bb2678b97 is described below
commit 7bb2678b97a8c8638c5af48ab4320cf65d661f6a
Author: PJ Fanning <pj...@users.noreply.github.com>
AuthorDate: Sun Sep 20 12:16:56 2026 +0100
FormulaEvaluator: tests for hidden rows (#1314)
* FormulaEvaluator: tests for hidden rows
Hidden rows are the one piece of sheet state besides cell contents that
the evaluator consults: SUBTOTAL with a function code above 100 skips
values in hidden rows via EvaluationSheet.isRowHidden. Existing coverage
was a single HSSF sample-file test of codes 109/102/103 with the rows
already hidden in the file.
Add BaseTestFormulaEvaluatorHiddenRows (HSSF and XSSF subclasses) on the
shared fixture: hiding a row after evaluation is not a cell change, so
results are stale until clearAllCachedResultValues; every 1xx code
skips hidden rows while 1-11 and all other functions count them;
single-cell arguments (the LazyRefEval branch in Subtotal); hidden rows
on another sheet; results flowing through dependent formulas alongside
cell notifications; nested subtotals; a collapsed outline group; and
hidden columns and missing rows, which are not hidden rows.
Also replace assertTrue(set.contains(..)) in the stability classifier
test with Hamcrest matchers.
Co-Authored-By: Claude Opus 5 <no...@anthropic.com>
* XSSFSheet: setRowGroupCollapsed(row, false) must show the group's rows again
isRowGroupHiddenByParent looked at the first row of the group to decide
whether an enclosing group hides it. That row is hidden whenever the
group itself is collapsed, so the check always said "hidden by parent"
and expandRow never unhid anything. Look at the row before the group
instead, as RowRecordsAggregate does for HSSF.
TestXSSFSheet.setRowGroupCollapsed asserted the old behaviour (rows
still hidden after expanding); the hidden-rows evaluator test now
covers collapse and expand in both formats.
Co-Authored-By: Claude Opus 5 <no...@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <no...@anthropic.com>
---
.../org/apache/poi/xssf/usermodel/XSSFSheet.java | 15 +-
.../TestXSSFFormulaEvaluatorHiddenRows.java | 28 +++
.../apache/poi/xssf/usermodel/TestXSSFSheet.java | 21 +-
.../TestHSSFFormulaEvaluatorHiddenRows.java | 28 +++
.../BaseTestFormulaEvaluatorHiddenRows.java | 252 +++++++++++++++++++++
...aseTestFormulaEvaluatorStabilityClassifier.java | 41 ++--
6 files changed, 351 insertions(+), 34 deletions(-)
diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
index da8fbf31a0..ecdf689207 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
@@ -2837,19 +2837,18 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet, OoxmlSheetEx
endHidden = getRow(endOfOutlineGroupIdx).getCTRow().getHidden();
}
- // Look out outline details of start
+ // Look out outline details of start: the row *before* the group is the one that tells
+ // whether an enclosing group hides this one (the group's own first row is hidden whenever
+ // the group itself is collapsed, so it says nothing about a parent)
int startLevel;
boolean startHidden;
- int startOfOutlineGroupIdx = findStartOfRowOutlineGroup(row);
- if (startOfOutlineGroupIdx < 0
- || getRow(startOfOutlineGroupIdx) == null) {
+ int rowBeforeGroupIdx = findStartOfRowOutlineGroup(row) - 1;
+ if (rowBeforeGroupIdx < 0 || getRow(rowBeforeGroupIdx) == null) {
startLevel = 0;
startHidden = false;
} else {
- startLevel = getRow(startOfOutlineGroupIdx).getCTRow()
- .getOutlineLevel();
- startHidden = getRow(startOfOutlineGroupIdx).getCTRow()
- .getHidden();
+ startLevel = getRow(rowBeforeGroupIdx).getCTRow().getOutlineLevel();
+ startHidden = getRow(rowBeforeGroupIdx).getCTRow().getHidden();
}
if (endLevel > startLevel) {
return endHidden;
diff --git a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluatorHiddenRows.java b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluatorHiddenRows.java
new file mode 100644
index 0000000000..2ab39fa0f0
--- /dev/null
+++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluatorHiddenRows.java
@@ -0,0 +1,28 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+package org.apache.poi.xssf.usermodel;
+
+import org.apache.poi.ss.usermodel.BaseTestFormulaEvaluatorHiddenRows;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+
+final class TestXSSFFormulaEvaluatorHiddenRows extends BaseTestFormulaEvaluatorHiddenRows {
+
+ TestXSSFFormulaEvaluatorHiddenRows() {
+ super(XSSFITestDataProvider.instance);
+ }
+}
diff --git a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
index 88ba99447c..fcf194fb41 100644
--- a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
+++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
@@ -891,10 +891,9 @@ public final class TestXSSFSheet extends BaseTestXSheet {
}
/**
- * TODO - while this is internally consistent, I'm not
- * completely clear in all cases what it's supposed to
- * be doing... Someone who understands the goals a little
- * better should really review this!
+ * Collapsing the inner group (rows 7-14) hides its rows and marks the row after it as
+ * collapsed; expanding it again shows them, as the enclosing group (rows 5-14) is not
+ * collapsed. The outer rows 5-6 and the separate group at 16-19 are never affected.
*/
@Test
void setRowGroupCollapsed() throws IOException {
@@ -922,6 +921,7 @@ public final class TestXSSFSheet extends BaseTestXSheet {
//collapsed
sheet1.setRowGroupCollapsed(7, true);
+ assertTrue(sheet1.getRow(15).getCTRow().getCollapsed());
assertFalse(sheet1.getRow(6).getCTRow().isSetCollapsed());
assertFalse(sheet1.getRow(6).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(7).getCTRow().isSetCollapsed());
@@ -941,11 +941,12 @@ public final class TestXSSFSheet extends BaseTestXSheet {
assertFalse(sheet1.getRow(6).getCTRow().isSetCollapsed());
assertFalse(sheet1.getRow(6).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(7).getCTRow().isSetCollapsed());
- assertTrue(sheet1.getRow(7).getCTRow().isSetHidden());
+ assertFalse(sheet1.getRow(7).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(9).getCTRow().isSetCollapsed());
- assertTrue(sheet1.getRow(9).getCTRow().isSetHidden());
+ assertFalse(sheet1.getRow(9).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(14).getCTRow().isSetCollapsed());
- assertTrue(sheet1.getRow(14).getCTRow().isSetHidden());
+ assertFalse(sheet1.getRow(14).getCTRow().isSetHidden());
+ assertFalse(sheet1.getRow(15).getCTRow().isSetCollapsed());
assertFalse(sheet1.getRow(16).getCTRow().isSetCollapsed());
assertFalse(sheet1.getRow(16).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(18).getCTRow().isSetCollapsed());
@@ -959,11 +960,11 @@ public final class TestXSSFSheet extends BaseTestXSheet {
assertFalse(sheet1.getRow(6).getCTRow().isSetCollapsed());
assertFalse(sheet1.getRow(6).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(7).getCTRow().isSetCollapsed());
- assertTrue(sheet1.getRow(7).getCTRow().isSetHidden());
+ assertFalse(sheet1.getRow(7).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(9).getCTRow().isSetCollapsed());
- assertTrue(sheet1.getRow(9).getCTRow().isSetHidden());
+ assertFalse(sheet1.getRow(9).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(14).getCTRow().isSetCollapsed());
- assertTrue(sheet1.getRow(14).getCTRow().isSetHidden());
+ assertFalse(sheet1.getRow(14).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(16).getCTRow().isSetCollapsed());
assertFalse(sheet1.getRow(16).getCTRow().isSetHidden());
assertFalse(sheet1.getRow(18).getCTRow().isSetCollapsed());
diff --git a/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluatorHiddenRows.java b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluatorHiddenRows.java
new file mode 100644
index 0000000000..0457911c57
--- /dev/null
+++ b/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluatorHiddenRows.java
@@ -0,0 +1,28 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import org.apache.poi.hssf.HSSFITestDataProvider;
+import org.apache.poi.ss.usermodel.BaseTestFormulaEvaluatorHiddenRows;
+
+final class TestHSSFFormulaEvaluatorHiddenRows extends BaseTestFormulaEvaluatorHiddenRows {
+
+ TestHSSFFormulaEvaluatorHiddenRows() {
+ super(HSSFITestDataProvider.instance);
+ }
+}
diff --git a/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestFormulaEvaluatorHiddenRows.java b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestFormulaEvaluatorHiddenRows.java
new file mode 100644
index 0000000000..6f7de64ae9
--- /dev/null
+++ b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestFormulaEvaluatorHiddenRows.java
@@ -0,0 +1,252 @@
+/* ====================================================================
+ 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.
+==================================================================== */
+
+package org.apache.poi.ss.usermodel;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.util.CellReference;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests formula evaluation against hidden rows. Hidden rows are the one piece of sheet state
+ * besides cell contents that the evaluator consults: {@code SUBTOTAL} with a function code above
+ * 100 skips values in hidden rows (via {@code EvaluationSheet.isRowHidden}), while every other
+ * function, and {@code SUBTOTAL} with codes 1-11, counts them.
+ * <p>
+ * Hiding a row changes results without any cell changing, so no {@code notify*} call describes
+ * it; like a shift, it needs {@link FormulaEvaluator#clearAllCachedResultValues()} (see
+ * {@link #afterVisibilityChange()}).
+ *
+ * @see BaseTestFormulaEvaluatorFixture for the workbook the tests run against
+ */
+public abstract class BaseTestFormulaEvaluatorHiddenRows extends BaseTestFormulaEvaluatorFixture {
+
+ protected BaseTestFormulaEvaluatorHiddenRows(ITestDataProvider testDataProvider) {
+ super(testDataProvider);
+ }
+
+ /**
+ * Called after rows were hidden or shown. Visibility is not a cell change, so there is no
+ * notification for it and the cached results have to be discarded.
+ */
+ protected void afterVisibilityChange() {
+ fe.clearAllCachedResultValues();
+ }
+
+ /** puts a formula into a (possibly new) cell of the Data sheet and tells the evaluator */
+ protected Cell formula(String ref, String formula) {
+ CellReference cr = new CellReference(ref);
+ Row row = data.getRow(cr.getRow());
+ if (row == null) {
+ row = data.createRow(cr.getRow());
+ }
+ Cell cell = row.createCell(cr.getCol());
+ cell.setCellFormula(formula);
+ fe.notifySetFormula(cell);
+ return cell;
+ }
+
+ protected void hideRow(Sheet sheet, int rowIndex, boolean hidden) {
+ sheet.getRow(rowIndex).setZeroHeight(hidden);
+ }
+
+ @Test
+ void subtotalAboveHundredSkipsHiddenRowsOnlyAfterCacheIsCleared() {
+ formula("E6", "SUBTOTAL(109,A2:A4)");
+ formula("E7", "SUBTOTAL(9,A2:A4)");
+ assertEquals(60, num("E6"), DELTA);
+ assertEquals(60, num("E7"), DELTA);
+
+ // hide the Gadget row
+ hideRow(data, 2, true);
+ // nothing in the workbook's cells changed, so the cached results are still served
+ assertEquals(60, num("E6"), DELTA);
+
+ afterVisibilityChange();
+ assertEquals(40, num("E6"), DELTA);
+ // codes 1-11 count hidden rows
+ assertEquals(60, num("E7"), DELTA);
+ // and so does everything else
+ assertEquals(60, num("A6"), DELTA);
+ assertEquals(21, num("C6"), DELTA);
+ assertEquals(170, num("D6"), DELTA);
+ assertEquals(2, num("C7"), DELTA);
+
+ hideRow(data, 2, false);
+ afterVisibilityChange();
+ assertEquals(60, num("E6"), DELTA);
+ }
+
+ @Test
+ void everyAggregateCodeAboveHundredSkipsHiddenRows() {
+ formula("E2", "SUBTOTAL(101,A2:A4)"); // AVERAGE
+ formula("E3", "SUBTOTAL(102,A2:A4)"); // COUNT
+ formula("E4", "SUBTOTAL(103,B2:B4)"); // COUNTA
+ formula("E6", "SUBTOTAL(104,A2:A4)"); // MAX
+ formula("E7", "SUBTOTAL(105,A2:A4)"); // MIN
+ formula("E8", "SUBTOTAL(106,C2:C4)"); // PRODUCT
+ formula("E9", "SUBTOTAL(109,A2:A4)"); // SUM
+ assertEquals(20, num("E2"), DELTA);
+ assertEquals(3, num("E3"), DELTA);
+ assertEquals(3, num("E4"), DELTA);
+ assertEquals(30, num("E6"), DELTA);
+ assertEquals(10, num("E7"), DELTA);
+ assertEquals(315, num("E8"), DELTA);
+ assertEquals(60, num("E9"), DELTA);
+
+ // hide the Widget row (10, "Widget", 5)
+ hideRow(data, 1, true);
+ afterVisibilityChange();
+ assertEquals(25, num("E2"), DELTA);
+ assertEquals(2, num("E3"), DELTA);
+ assertEquals(2, num("E4"), DELTA);
+ assertEquals(30, num("E6"), DELTA);
+ assertEquals(20, num("E7"), DELTA);
+ assertEquals(63, num("E8"), DELTA);
+ assertEquals(50, num("E9"), DELTA);
+
+ // hide the Gizmo row too (30, "Gizmo", 9)
+ hideRow(data, 3, true);
+ afterVisibilityChange();
+ assertEquals(20, num("E2"), DELTA);
+ assertEquals(1, num("E3"), DELTA);
+ assertEquals(1, num("E4"), DELTA);
+ assertEquals(20, num("E6"), DELTA);
+ assertEquals(20, num("E7"), DELTA);
+ assertEquals(7, num("E8"), DELTA);
+ assertEquals(20, num("E9"), DELTA);
+ }
+
+ @Test
+ void subtotalOverSingleCellReferencesSkipsHiddenRows() {
+ // single-cell arguments take a different path from areas inside SUBTOTAL
+ formula("E6", "SUBTOTAL(109,A2,A3,A4)");
+ formula("E7", "SUBTOTAL(9,A2,A3,A4)");
+ formula("E8", "SUBTOTAL(103,B2,B3,B4)");
+ assertEquals(60, num("E6"), DELTA);
+
+ hideRow(data, 1, true);
+ afterVisibilityChange();
+ assertEquals(50, num("E6"), DELTA);
+ assertEquals(60, num("E7"), DELTA);
+ assertEquals(2, num("E8"), DELTA);
+ }
+
+ @Test
+ void subtotalSkipsHiddenRowsOnOtherSheets() {
+ formula("E6", "SUBTOTAL(109,Prices!B2:B4)");
+ formula("E7", "SUBTOTAL(103,Prices!A2:A4)");
+ assertEquals(7.5, num("E6"), DELTA);
+ assertEquals(3, num("E7"), DELTA);
+
+ hideRow(prices, 2, true);
+ afterVisibilityChange();
+ assertEquals(5, num("E6"), DELTA);
+ assertEquals(2, num("E7"), DELTA);
+ // hidden rows on the Data sheet do not affect a range on the Prices sheet
+ hideRow(data, 2, true);
+ afterVisibilityChange();
+ assertEquals(5, num("E6"), DELTA);
+ // and the lookups still see the hidden Prices row: VLOOKUP does not care about visibility
+ assertEquals(2.5, num("D3"), DELTA);
+ }
+
+ @Test
+ void hiddenRowResultsFlowThroughDependentFormulas() {
+ formula("E6", "SUBTOTAL(109,A2:A4)");
+ formula("E7", "E6*2");
+ formula("E8", "IF(E7>100,\"big\",\"small\")");
+ assertEquals(120, num("E7"), DELTA);
+ assertEquals("big", str("E8"));
+
+ hideRow(data, 3, true);
+ afterVisibilityChange();
+ assertEquals(30, num("E6"), DELTA);
+ assertEquals(60, num("E7"), DELTA);
+ assertEquals("small", str("E8"));
+
+ // cell notifications keep working alongside: a visible input changes
+ cell("A2").setCellValue(60);
+ fe.notifyUpdateCell(cell("A2"));
+ assertEquals(80, num("E6"), DELTA);
+ assertEquals("big", str("E8"));
+ // a change in the hidden row is tracked too, it just does not count
+ cell("A4").setCellValue(1000);
+ fe.notifyUpdateCell(cell("A4"));
+ assertEquals(80, num("E6"), DELTA);
+ assertEquals(1080, num("A6"), DELTA);
+ }
+
+ @Test
+ void nestedSubtotalsAreIgnoredWhetherHiddenOrNot() {
+ formula("E2", "SUBTOTAL(109,A2:A2)");
+ formula("E3", "SUBTOTAL(109,A3:A3)");
+ formula("E4", "A4");
+ // a SUBTOTAL over a range containing other SUBTOTALs ignores them, so only E4 counts
+ formula("E6", "SUBTOTAL(109,E2:E4)");
+ formula("E7", "SUBTOTAL(9,E2:E4)");
+ assertEquals(30, num("E6"), DELTA);
+ assertEquals(30, num("E7"), DELTA);
+
+ hideRow(data, 3, true);
+ afterVisibilityChange();
+ assertEquals(0, num("E6"), DELTA);
+ assertEquals(30, num("E7"), DELTA);
+ }
+
+ @Test
+ void collapsedOutlineGroupHidesItsRows() {
+ formula("E6", "SUBTOTAL(109,A2:A4)");
+ formula("E7", "SUBTOTAL(9,A2:A4)");
+ assertEquals(60, num("E6"), DELTA);
+
+ // collapsing a group hides its rows, which is what SUBTOTAL 1xx looks at
+ data.groupRow(1, 2);
+ data.setRowGroupCollapsed(1, true);
+ assertTrue(data.getRow(1).getZeroHeight());
+ assertTrue(data.getRow(2).getZeroHeight());
+ afterVisibilityChange();
+ assertEquals(30, num("E6"), DELTA);
+ assertEquals(60, num("E7"), DELTA);
+
+ // expanding it shows them again
+ data.setRowGroupCollapsed(1, false);
+ assertFalse(data.getRow(1).getZeroHeight());
+ assertFalse(data.getRow(2).getZeroHeight());
+ afterVisibilityChange();
+ assertEquals(60, num("E6"), DELTA);
+ }
+
+ @Test
+ void hiddenColumnsAndMissingRowsAreNotHiddenRows() {
+ // SUBTOTAL only ever skips hidden rows, never hidden columns
+ formula("E6", "SUBTOTAL(109,A2:A4)");
+ data.setColumnHidden(0, true);
+ afterVisibilityChange();
+ assertEquals(60, num("E6"), DELTA);
+
+ // a row that does not exist (the spare row 5) is blank, not hidden
+ formula("E7", "SUBTOTAL(109,A2:A5)");
+ formula("E8", "SUBTOTAL(102,A2:A5)");
+ assertEquals(60, num("E7"), DELTA);
+ assertEquals(3, num("E8"), DELTA);
+ }
+}
diff --git a/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestFormulaEvaluatorStabilityClassifier.java b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestFormulaEvaluatorStabilityClassifier.java
index d2c8d87faa..cc77b40181 100644
--- a/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestFormulaEvaluatorStabilityClassifier.java
+++ b/poi/src/test/java/org/apache/poi/ss/usermodel/BaseTestFormulaEvaluatorStabilityClassifier.java
@@ -17,10 +17,16 @@
package org.apache.poi.ss.usermodel;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.everyItem;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.in;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -167,22 +173,25 @@ public abstract class BaseTestFormulaEvaluatorStabilityClassifier extends BaseTe
int d = dataIndex();
int p = pricesIndex();
- // plain inputs on the data sheet
- assertTrue(asked.contains(d + ":1:0"), "A2");
- assertTrue(asked.contains(d + ":3:2"), "C4");
- // the lookup table, read through a cross-sheet area reference
- assertTrue(asked.contains(p + ":1:0"), "Prices!A2");
- assertTrue(asked.contains(p + ":3:1"), "Prices!B4");
- // formula cells are classified too, both when evaluated directly and via the defined name
- assertTrue(asked.contains(d + ":5:0"), "A6");
- assertTrue(asked.contains(d + ":7:1"), "B8");
+ assertThat(asked, hasItems(
+ // plain inputs on the data sheet
+ d + ":1:0", // A2
+ d + ":3:2", // C4
+ // the lookup table, read through a cross-sheet area reference
+ p + ":1:0", // Prices!A2
+ p + ":3:1", // Prices!B4
+ // formula cells are classified too, both when evaluated directly and via the defined name
+ d + ":5:0", // A6
+ d + ":7:1" // B8
+ ));
// cells nothing refers to are never asked about
- assertFalse(asked.contains(d + ":0:0"), "Data header");
- assertFalse(asked.contains(p + ":0:0"), "Prices header");
- assertFalse(asked.contains(d + ":4:0"), "spare row");
+ assertThat("Data header", asked, not(hasItem(d + ":0:0")));
+ assertThat("Prices header", asked, not(hasItem(p + ":0:0")));
+ assertThat("spare row", asked, not(hasItem(d + ":4:0")));
+ Set<String> sheets = new HashSet<>();
for (String key : asked) {
- int sheet = Integer.parseInt(key.substring(0, key.indexOf(':')));
- assertTrue(sheet == d || sheet == p, "unexpected sheet index in " + key);
+ sheets.add(key.substring(0, key.indexOf(':')));
}
+ assertThat(sheets, everyItem(is(in(Arrays.asList(String.valueOf(d), String.valueOf(p))))));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org