Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

BaseTestFunctionsFromSpreadsheet.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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.ss.formula.functions;
  16. import static org.junit.Assert.assertEquals;
  17. import static org.junit.Assert.assertNotEquals;
  18. import static org.junit.Assert.assertNotNull;
  19. import static org.junit.Assert.assertTrue;
  20. import static org.junit.Assert.fail;
  21. import java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.List;
  24. import java.util.Locale;
  25. import org.apache.poi.hssf.HSSFTestDataSamples;
  26. import org.apache.poi.hssf.usermodel.HSSFCell;
  27. import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
  28. import org.apache.poi.hssf.usermodel.HSSFRow;
  29. import org.apache.poi.hssf.usermodel.HSSFSheet;
  30. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  31. import org.apache.poi.ss.util.CellReference;
  32. import org.apache.poi.ss.formula.eval.ErrorEval;
  33. import org.apache.poi.ss.usermodel.CellType;
  34. import org.apache.poi.ss.usermodel.CellValue;
  35. import org.junit.Test;
  36. import org.junit.runner.RunWith;
  37. import org.junit.runners.Parameterized;
  38. import org.junit.runners.Parameterized.Parameter;
  39. @RunWith(Parameterized.class)
  40. public abstract class BaseTestFunctionsFromSpreadsheet {
  41. /**
  42. * This class defines constants for navigating around the test data spreadsheet used for these tests.
  43. */
  44. interface SS {
  45. /** Name of the first sheet in the spreadsheet (contains comments) */
  46. String README_SHEET_NAME = "Read Me";
  47. /** Row (zero-based) in each sheet where the evaluation cases start. */
  48. int START_TEST_CASES_ROW_INDEX = 4; // Row '5'
  49. /** Index of the column that contains the function names */
  50. int COLUMN_INDEX_MARKER = 0; // Column 'A'
  51. int COLUMN_INDEX_EVALUATION = 1; // Column 'B'
  52. int COLUMN_INDEX_EXPECTED_RESULT = 2; // Column 'C'
  53. int COLUMN_ROW_COMMENT = 3; // Column 'D'
  54. /** Used to indicate when there are no more test cases on the current sheet */
  55. String TEST_CASES_END_MARKER = "<end>";
  56. /** Used to indicate that the test on the current row should be ignored */
  57. String SKIP_CURRENT_TEST_CASE_MARKER = "<skip>";
  58. }
  59. @Parameter()
  60. public String testName;
  61. @Parameter(value = 1)
  62. public String filename;
  63. @Parameter(value = 2)
  64. public HSSFSheet sheet;
  65. @Parameter(value = 3)
  66. public int formulasRowIdx;
  67. @Parameter(value = 4)
  68. public HSSFFormulaEvaluator evaluator;
  69. @Parameter(value = 5)
  70. public int precisionColumnIndex;
  71. protected static Collection<Object[]> data(Class<? extends BaseTestFunctionsFromSpreadsheet> clazz, String filename) throws Exception {
  72. HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(filename);
  73. confirmReadMeSheet(workbook, clazz);
  74. List<Object[]> data = new ArrayList<>();
  75. int nSheets = workbook.getNumberOfSheets();
  76. for(int sheetIdx=1; sheetIdx< nSheets; sheetIdx++) {
  77. HSSFSheet sheet = workbook.getSheetAt(sheetIdx);
  78. processFunctionGroup(data, sheet, SS.START_TEST_CASES_ROW_INDEX, filename);
  79. }
  80. workbook.close();
  81. return data;
  82. }
  83. private static void processFunctionGroup(List<Object[]> data, HSSFSheet sheet, final int startRowIndex, String filename) {
  84. HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet.getWorkbook());
  85. int precisionColumnIndex = -1;
  86. HSSFRow precisionRow = sheet.getWorkbook().getSheetAt(0).getRow(11);
  87. HSSFCell precisionCell = precisionRow == null ? null : precisionRow.getCell(0);
  88. if(precisionCell != null && precisionCell.getCellType() == CellType.NUMERIC){
  89. precisionColumnIndex = (int)precisionCell.getNumericCellValue();
  90. }
  91. String currentGroupComment = "";
  92. final int maxRows = sheet.getLastRowNum()+1;
  93. for(int rowIndex=startRowIndex; rowIndex<maxRows; rowIndex++) {
  94. HSSFRow r = sheet.getRow(rowIndex);
  95. if(r == null) {
  96. continue;
  97. }
  98. String newMarkerValue = getCellTextValue(r, SS.COLUMN_INDEX_MARKER, "marker");
  99. if(SS.TEST_CASES_END_MARKER.equalsIgnoreCase(newMarkerValue)) {
  100. // normal exit point
  101. return;
  102. }
  103. if(SS.SKIP_CURRENT_TEST_CASE_MARKER.equalsIgnoreCase(newMarkerValue)) {
  104. // currently disabled test case row
  105. continue;
  106. }
  107. if(newMarkerValue != null) {
  108. currentGroupComment = newMarkerValue;
  109. }
  110. HSSFCell evalCell = r.getCell(SS.COLUMN_INDEX_EVALUATION);
  111. if (evalCell == null || evalCell.getCellType() != CellType.FORMULA) {
  112. continue;
  113. }
  114. String rowComment = getCellTextValue(r, SS.COLUMN_ROW_COMMENT, "row comment");
  115. String testName = (currentGroupComment+'\n'+rowComment).replace("null", "").trim().replace("\n", " - ");
  116. if (testName.isEmpty()) {
  117. testName = evalCell.getCellFormula();
  118. }
  119. data.add(new Object[]{testName, filename, sheet, rowIndex, evaluator, precisionColumnIndex});
  120. }
  121. fail("Missing end marker '" + SS.TEST_CASES_END_MARKER + "' on sheet '" + sheet.getSheetName() + "'");
  122. }
  123. @Test
  124. public void processFunctionRow() throws Exception {
  125. HSSFRow r = sheet.getRow(formulasRowIdx);
  126. HSSFCell evalCell = r.getCell(SS.COLUMN_INDEX_EVALUATION);
  127. HSSFCell expectedCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
  128. HSSFCell precisionCell = r.getCell(precisionColumnIndex);
  129. CellReference cr = new CellReference(sheet.getSheetName(), formulasRowIdx, evalCell.getColumnIndex(), false, false);
  130. String msg = String.format(Locale.ROOT, "In %s %s {=%s} '%s'"
  131. , filename, cr.formatAsString(), evalCell.getCellFormula(), testName);
  132. CellValue actualValue = evaluator.evaluate(evalCell);
  133. assertNotNull(msg + " - Bad setup data expected value is null", expectedCell);
  134. assertNotNull(msg + " - actual value was null", actualValue);
  135. if (expectedCell.getCellType() == CellType.ERROR) {
  136. int expectedErrorCode = expectedCell.getErrorCellValue();
  137. assertEquals(msg, CellType.ERROR, actualValue.getCellType());
  138. assertEquals(msg, ErrorEval.getText(expectedErrorCode), actualValue.formatAsString());
  139. assertEquals(msg, expectedErrorCode, actualValue.getErrorValue());
  140. assertEquals(msg, ErrorEval.getText(expectedErrorCode), ErrorEval.getText(actualValue.getErrorValue()));
  141. return;
  142. }
  143. // unexpected error
  144. assertNotEquals(msg, CellType.ERROR, actualValue.getCellType());
  145. assertNotEquals(msg, formatValue(expectedCell), ErrorEval.getText(actualValue.getErrorValue()));
  146. // wrong type error
  147. assertEquals(msg, expectedCell.getCellType(), actualValue.getCellType());
  148. final CellType expectedCellType = expectedCell.getCellType();
  149. switch (expectedCellType) {
  150. case BOOLEAN:
  151. assertEquals(msg, expectedCell.getBooleanCellValue(), actualValue.getBooleanValue());
  152. break;
  153. case FORMULA: // will never be used, since we will call method after formula evaluation
  154. fail("Cannot expect formula as result of formula evaluation: " + msg);
  155. case NUMERIC:
  156. double precision = precisionCell != null && precisionCell.getCellType() == CellType.NUMERIC
  157. ? precisionCell.getNumericCellValue() : 0.0;
  158. assertEquals(expectedCell.getNumericCellValue(), actualValue.getNumberValue(), precision);
  159. break;
  160. case STRING:
  161. assertEquals(msg, expectedCell.getRichStringCellValue().getString(), actualValue.getStringValue());
  162. break;
  163. default:
  164. fail("Unexpected cell type: " + expectedCellType);
  165. }
  166. }
  167. /**
  168. * Asserts that the 'read me' comment page exists, and has this class' name in one of the
  169. * cells. This back-link is to make it easy to find this class if a reader encounters the
  170. * spreadsheet first.
  171. */
  172. private static void confirmReadMeSheet(HSSFWorkbook workbook, Class<? extends BaseTestFunctionsFromSpreadsheet> clazz) {
  173. String firstSheetName = workbook.getSheetName(0);
  174. assertTrue("First sheet's name was '" + firstSheetName + "' but expected '" + SS.README_SHEET_NAME + "'",
  175. firstSheetName.equalsIgnoreCase(SS.README_SHEET_NAME));
  176. HSSFSheet sheet = workbook.getSheetAt(0);
  177. String specifiedClassName = sheet.getRow(2).getCell(0).getRichStringCellValue().getString();
  178. assertEquals("Test class name in spreadsheet comment", clazz.getName(), specifiedClassName);
  179. HSSFRow precisionRow = sheet.getRow(11);
  180. HSSFCell precisionCell = precisionRow == null ? null : precisionRow.getCell(0);
  181. if(precisionCell != null && precisionCell.getCellType() == CellType.NUMERIC){
  182. }
  183. }
  184. /**
  185. * @return <code>null</code> if cell is missing, empty or blank
  186. */
  187. private static String getCellTextValue(HSSFRow r, int colIndex, String columnName) {
  188. if(r == null) {
  189. return null;
  190. }
  191. HSSFCell cell = r.getCell(colIndex);
  192. if(cell == null) {
  193. return null;
  194. }
  195. if(cell.getCellType() == CellType.BLANK) {
  196. return null;
  197. }
  198. if(cell.getCellType() == CellType.STRING) {
  199. return cell.getRichStringCellValue().getString();
  200. }
  201. fail("Bad cell type for '" + columnName + "' column: ("
  202. + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")");
  203. return "";
  204. }
  205. private static String formatValue(HSSFCell expectedCell) {
  206. switch (expectedCell.getCellType()) {
  207. case BLANK: return "<blank>";
  208. case BOOLEAN: return Boolean.toString(expectedCell.getBooleanCellValue());
  209. case NUMERIC: return Double.toString(expectedCell.getNumericCellValue());
  210. case STRING: return expectedCell.getRichStringCellValue().getString();
  211. default: fail("Unexpected cell type of expected value (" + expectedCell.getCellType() + ")");
  212. }
  213. return "";
  214. }
  215. }