You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestSharedValueManager.java 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hssf.record.aggregates;
  16. import java.util.Collection;
  17. import java.util.HashMap;
  18. import junit.framework.AssertionFailedError;
  19. import junit.framework.TestCase;
  20. import org.apache.poi.hssf.HSSFTestDataSamples;
  21. import org.apache.poi.hssf.record.Record;
  22. import org.apache.poi.hssf.record.SharedFormulaRecord;
  23. import org.apache.poi.hssf.usermodel.HSSFCell;
  24. import org.apache.poi.hssf.usermodel.HSSFSheet;
  25. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  26. import org.apache.poi.hssf.usermodel.RecordInspector;
  27. /**
  28. * Tests for {@link SharedValueManager}
  29. *
  30. * @author Josh Micich
  31. */
  32. public final class TestSharedValueManager extends TestCase {
  33. /**
  34. * This Excel workbook contains two sheets that each have a pair of overlapping shared formula
  35. * ranges. The first sheet has one row and one column shared formula ranges which intersect.
  36. * The second sheet has two column shared formula ranges - one contained within the other.
  37. * These shared formula ranges were created by fill-dragging a single cell formula across the
  38. * desired region. The larger shared formula ranges were placed first.<br/>
  39. *
  40. * There are probably many ways to produce similar effects, but it should be noted that Excel
  41. * is quite temperamental in this regard. Slight variations in technique can cause the shared
  42. * formulas to spill out into plain formula records (which would make these tests pointless).
  43. *
  44. */
  45. private static final String SAMPLE_FILE_NAME = "overlapSharedFormula.xls";
  46. /**
  47. * Some of these bugs are intermittent, and the test author couldn't think of a way to write
  48. * test code to hit them bug deterministically. The reason for the unpredictability is that
  49. * the bugs depended on the {@link SharedFormulaRecord}s being searched in a particular order.
  50. * At the time of writing of the test, the order was being determined by the call to {@link
  51. * Collection#toArray(Object[])} on {@link HashMap#values()} where the items in the map were
  52. * using default {@link Object#hashCode()}<br/>
  53. */
  54. private static final int MAX_ATTEMPTS=5;
  55. /**
  56. * This bug happened when there were two or more shared formula ranges that overlapped. POI
  57. * would sometimes associate formulas in the overlapping region with the wrong shared formula
  58. */
  59. public void testPartiallyOverlappingRanges() {
  60. Record[] records;
  61. int attempt=1;
  62. do {
  63. HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(SAMPLE_FILE_NAME);
  64. HSSFSheet sheet = wb.getSheetAt(0);
  65. RecordInspector.getRecords(sheet, 0);
  66. assertEquals("1+1", sheet.getRow(2).getCell(0).getCellFormula());
  67. if ("1+1".equals(sheet.getRow(3).getCell(0).getCellFormula())) {
  68. throw new AssertionFailedError("Identified bug - wrong shared formula record chosen"
  69. + " (attempt " + attempt + ")");
  70. }
  71. assertEquals("2+2", sheet.getRow(3).getCell(0).getCellFormula());
  72. records = RecordInspector.getRecords(sheet, 0);
  73. } while (attempt++ < MAX_ATTEMPTS);
  74. int count=0;
  75. for (int i = 0; i < records.length; i++) {
  76. if (records[i] instanceof SharedFormulaRecord) {
  77. count++;
  78. }
  79. }
  80. assertEquals(2, count);
  81. }
  82. /**
  83. * This bug occurs for similar reasons to the bug in {@link #testPartiallyOverlappingRanges()}
  84. * but the symptoms are much uglier - serialization fails with {@link NullPointerException}.<br/>
  85. */
  86. public void testCompletelyOverlappedRanges() {
  87. Record[] records;
  88. int attempt=1;
  89. do {
  90. HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(SAMPLE_FILE_NAME);
  91. HSSFSheet sheet = wb.getSheetAt(1);
  92. try {
  93. records = RecordInspector.getRecords(sheet, 0);
  94. } catch (NullPointerException e) {
  95. throw new AssertionFailedError("Identified bug " +
  96. "- cannot reserialize completely overlapped shared formula"
  97. + " (attempt " + attempt + ")");
  98. }
  99. } while (attempt++ < MAX_ATTEMPTS);
  100. int count=0;
  101. for (int i = 0; i < records.length; i++) {
  102. if (records[i] instanceof SharedFormulaRecord) {
  103. count++;
  104. }
  105. }
  106. assertEquals(2, count);
  107. }
  108. /**
  109. * Tests fix for a bug in the way shared formula cells are associated with shared formula
  110. * records. Prior to this fix, POI would attempt to use the upper left corner of the
  111. * shared formula range as the locator cell. The correct cell to use is the 'first cell'
  112. * in the shared formula group which is not always the top left cell. This is possible
  113. * because shared formula groups may be sparse and may overlap.<br/>
  114. *
  115. * Two existing sample files (15228.xls and ex45046-21984.xls) had similar issues.
  116. * These were not explored fully, but seem to be fixed now.
  117. */
  118. public void testRecalculateFormulas47747() {
  119. /*
  120. * ex47747-sharedFormula.xls is a heavily cut-down version of the spreadsheet from
  121. * the attachment (id=24176) in Bugzilla 47747. This was done to make the sample
  122. * file smaller, which hopefully allows the special data encoding condition to be
  123. * seen more easily. Care must be taken when modifying this file since the
  124. * special conditions are easily destroyed (which would make this test useless).
  125. * It seems that removing the worksheet protection has made this more so - if the
  126. * current file is re-saved in Excel(2007) the bug condition disappears.
  127. *
  128. *
  129. * Using BiffViewer, one can see that there are two shared formula groups representing
  130. * the essentially same formula over ~20 cells. The shared group ranges overlap and
  131. * are A12:Q20 and A20:Q27. The locator cell ('first cell') for the second group is
  132. * Q20 which is not the top left cell of the enclosing range. It is this specific
  133. * condition which caused the bug to occur
  134. */
  135. HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex47747-sharedFormula.xls");
  136. // pick out a cell from within the second shared formula group
  137. HSSFCell cell = wb.getSheetAt(0).getRow(23).getCell(0);
  138. String formulaText;
  139. try {
  140. formulaText = cell.getCellFormula();
  141. // succeeds if the formula record has been associated
  142. // with the second shared formula group
  143. } catch (RuntimeException e) {
  144. // bug occurs if the formula record has been associated
  145. // with the first shared formula group
  146. if ("Shared Formula Conversion: Coding Error".equals(e.getMessage())) {
  147. throw new AssertionFailedError("Identified bug 47747");
  148. }
  149. throw e;
  150. }
  151. assertEquals("$AF24*A$7", formulaText);
  152. }
  153. }