Package org.apache.poi.hssf.record.formula.functions

Source Code of org.apache.poi.hssf.record.formula.functions.TestLookupFunctionsFromSpreadsheet$SS

/*
* 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.record.formula.functions;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;

import junit.framework.Assert;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;

import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
import org.apache.poi.hssf.util.CellReference;

/**
* Tests lookup functions (VLOOKUP, HLOOKUP, LOOKUP, MATCH) as loaded from a test data spreadsheet.<p/>
* These tests have been separated from the common function and operator tests because the lookup
* functions have more complex test cases and test data setup.
*
* Tests for bug fixes and specific/tricky behaviour can be found in the corresponding test class
* (<tt>TestXxxx</tt>) of the target (<tt>Xxxx</tt>) implementor, where execution can be observed
*  more easily.
*
* @author Josh Micich
*/
public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
 
  private static final class Result {
    public static final int SOME_EVALUATIONS_FAILED = -1;
    public static final int ALL_EVALUATIONS_SUCCEEDED = +1;
    public static final int NO_EVALUATIONS_FOUND = 0;
  }

  /**
   * This class defines constants for navigating around the test data spreadsheet used for these tests.
   */
  private static final class SS {
   
    /** Name of the test spreadsheet (found in the standard test data folder) */
    public final static String FILENAME = "LookupFunctionsTestCaseData.xls";
   
    /** Name of the first sheet in the spreadsheet (contains comments) */
    public final static String README_SHEET_NAME = "Read Me";
   
   
    /** Row (zero-based) in each sheet where the evaluation cases start.   */
    public static final int START_TEST_CASES_ROW_INDEX = 4; // Row '5'
    /**  Index of the column that contains the function names */
    public static final short COLUMN_INDEX_MARKER = 0; // Column 'A'
    public static final short COLUMN_INDEX_EVALUATION = 1; // Column 'B'
    public static final short COLUMN_INDEX_EXPECTED_RESULT = 2; // Column 'C'
    public static final short COLUMN_ROW_COMMENT = 3; // Column 'D'
 
    /** Used to indicate when there are no more test cases on the current sheet   */
    public static final String TEST_CASES_END_MARKER = "<end>";
    /** Used to indicate that the test on the current row should be ignored */
    public static final String SKIP_CURRENT_TEST_CASE_MARKER = "<skip>";
 
  }

   // Note - multiple failures are aggregated before ending. 
  // If one or more functions fail, a single AssertionFailedError is thrown at the end
  private int _sheetFailureCount;
  private int _sheetSuccessCount;
  private int _evaluationFailureCount;
  private int _evaluationSuccessCount;



  private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) {
    if (expected == null) {
      throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
    }
    if(actual == null) {
      throw new AssertionFailedError(msg + " - actual value was null");
    }
    if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
      confirmErrorResult(msg, expected.getErrorCellValue(), actual);
      return;
    }
    if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
      throw unexpectedError(msg, expected, actual.getErrorValue());
    }
    if(actual.getCellType() != expected.getCellType()) {
      throw wrongTypeError(msg, expected, actual);
    }
   
   
    switch (expected.getCellType()) {
      case HSSFCell.CELL_TYPE_BOOLEAN:
        assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
        break;
      case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
        throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
      case HSSFCell.CELL_TYPE_NUMERIC:
        assertEquals(expected.getNumericCellValue(), actual.getNumberValue(), 0.0);
        break;
      case HSSFCell.CELL_TYPE_STRING:
        assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
        break;
    }
  }


  private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) {
    return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was "
        + formatValue(actualValue)
        + " but the expected result was "
        + formatValue(expectedCell)
        );
  }
  private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) {
    return new AssertionFailedError(msgPrefix + " Error code ("
        + ErrorEval.getText(actualErrorCode)
        + ") was evaluated, but the expected result was "
        + formatValue(expected)
        );
  }


  private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) {
    if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) {
      throw new AssertionFailedError(msgPrefix + " Expected cell error ("
          + ErrorEval.getText(expectedErrorCode) + ") but actual value was "
          + formatValue(actual));
    }
    if(expectedErrorCode != actual.getErrorValue()) {
      throw new AssertionFailedError(msgPrefix + " Expected cell error code ("
          + ErrorEval.getText(expectedErrorCode)
          + ") but actual error code was ("
          + ErrorEval.getText(actual.getErrorValue())
          + ")");
    }
  }


  private static String formatValue(HSSFCell expecedCell) {
    switch (expecedCell.getCellType()) {
      case HSSFCell.CELL_TYPE_BLANK: return "<blank>";
      case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue());
      case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue());
      case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString();
    }
    throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")");
  }
  private static String formatValue(CellValue actual) {
    switch (actual.getCellType()) {
      case HSSFCell.CELL_TYPE_BLANK: return "<blank>";
      case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(actual.getBooleanValue());
      case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(actual.getNumberValue());
      case HSSFCell.CELL_TYPE_STRING: return actual.getRichTextStringValue().getString();
    }
    throw new RuntimeException("Unexpected cell type of evaluated value (" + actual.getCellType() + ")");
  }


  protected void setUp() throws Exception {
    _sheetFailureCount = 0;
    _sheetSuccessCount = 0;
    _evaluationFailureCount = 0;
    _evaluationSuccessCount = 0;
  }
 
  public void testFunctionsFromTestSpreadsheet() {
    HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME);
    
    confirmReadMeSheet(workbook);
    int nSheets = workbook.getNumberOfSheets();
    for(int i=1; i< nSheets; i++) {
      int sheetResult = processTestSheet(workbook, i, workbook.getSheetName(i));
      switch(sheetResult) {
        case Result.ALL_EVALUATIONS_SUCCEEDED: _sheetSuccessCount ++; break;
        case Result.SOME_EVALUATIONS_FAILED: _sheetFailureCount ++; break;
      }
    }
   
    // confirm results
    String successMsg = "There were "
        + _sheetSuccessCount + " successful sheets(s) and "
        + _evaluationSuccessCount + " function(s) without error";
     if(_sheetFailureCount > 0) {
      String msg = _sheetFailureCount + " sheets(s) failed with "
      + _evaluationFailureCount + " evaluation(s).  " + successMsg;
      throw new AssertionFailedError(msg);
    }
     if(false) { // normally no output for successful tests
       System.out.println(getClass().getName() + ": " + successMsg);
     }
  }

  private int processTestSheet(HSSFWorkbook workbook, int sheetIndex, String sheetName) {
    HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
    HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, workbook);
    int maxRows = sheet.getLastRowNum()+1;
    int result = Result.NO_EVALUATIONS_FOUND; // so far
   
    String currentGroupComment = null;
    for(int rowIndex=SS.START_TEST_CASES_ROW_INDEX; rowIndex<maxRows; rowIndex++) {
      HSSFRow r = sheet.getRow(rowIndex);
      String newMarkerValue = getMarkerColumnValue(r);
      if(r == null) {
        continue;
      }
      if(SS.TEST_CASES_END_MARKER.equalsIgnoreCase(newMarkerValue)) {
        // normal exit point
        return result;
      }
      if(SS.SKIP_CURRENT_TEST_CASE_MARKER.equalsIgnoreCase(newMarkerValue)) {
        // currently disabled test case row
        continue;
      }
      if(newMarkerValue != null) {
        currentGroupComment = newMarkerValue;
      }
      HSSFCell c = r.getCell(SS.COLUMN_INDEX_EVALUATION);
      if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
        continue;
      }
      evaluator.setCurrentRow(r);
      CellValue actualValue = evaluator.evaluate(c);
      HSSFCell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
      String rowComment = getRowCommentColumnValue(r);
     
      String msgPrefix = formatTestCaseDetails(sheetName, r.getRowNum(), c, currentGroupComment, rowComment);
      try {
        confirmExpectedResult(msgPrefix, expectedValueCell, actualValue);
        _evaluationSuccessCount ++;
        if(result != Result.SOME_EVALUATIONS_FAILED) {
          result = Result.ALL_EVALUATIONS_SUCCEEDED;
        }
      } catch (RuntimeException e) {
        _evaluationFailureCount ++;
        printShortStackTrace(System.err, e);
        result = Result.SOME_EVALUATIONS_FAILED;
      } catch (AssertionFailedError e) {
        _evaluationFailureCount ++;
        printShortStackTrace(System.err, e);
        result = Result.SOME_EVALUATIONS_FAILED;
      }
     
    }
    throw new RuntimeException("Missing end marker '" + SS.TEST_CASES_END_MARKER
        + "' on sheet '" + sheetName + "'");
   
  }


  private static String formatTestCaseDetails(String sheetName, int rowNum, HSSFCell c, String currentGroupComment,
      String rowComment) {
   
    StringBuffer sb = new StringBuffer();
    CellReference cr = new CellReference(sheetName, rowNum, c.getCellNum(), false, false);
    sb.append(cr.formatAsString());
    sb.append(" {=").append(c.getCellFormula()).append("}");
   
    if(currentGroupComment != null) {
      sb.append(" '");
      sb.append(currentGroupComment);
      if(rowComment != null) {
        sb.append(" - ");
        sb.append(rowComment);
      }
      sb.append("' ");
    } else {
      if(rowComment != null) {
        sb.append(" '");
        sb.append(rowComment);
        sb.append("' ");
      }
    }
   
    return sb.toString();
  }

  /**
   * Asserts that the 'read me' comment page exists, and has this class' name in one of the
   * cells.  This back-link is to make it easy to find this class if a reader encounters the
   * spreadsheet first.
   */
  private void confirmReadMeSheet(HSSFWorkbook workbook) {
    String firstSheetName = workbook.getSheetName(0);
    if(!firstSheetName.equalsIgnoreCase(SS.README_SHEET_NAME)) {
      throw new RuntimeException("First sheet's name was '" + firstSheetName + "' but expected '" + SS.README_SHEET_NAME + "'");
    }
    HSSFSheet sheet = workbook.getSheetAt(0);
    String specifiedClassName = sheet.getRow(2).getCell((short)0).getRichStringCellValue().getString();
    assertEquals("Test class name in spreadsheet comment", getClass().getName(), specifiedClassName);
   
  }


  /**
   * Useful to keep output concise when expecting many failures to be reported by this test case
   */
  private static void printShortStackTrace(PrintStream ps, Throwable e) {
    StackTraceElement[] stes = e.getStackTrace();
   
    int startIx = 0;
    // skip any top frames inside junit.framework.Assert
    while(startIx<stes.length) {
      if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
        break;
      }
      startIx++;
    }
    // skip bottom frames (part of junit framework)
    int endIx = startIx+1;
    while(endIx < stes.length) {
      if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
        break;
      }
      endIx++;
    }
    if(startIx >= endIx) {
      // something went wrong. just print the whole stack trace
      e.printStackTrace(ps);
    }
    endIx -= 4; // skip 4 frames of reflection invocation
    ps.println(e.toString());
    for(int i=startIx; i<endIx; i++) {
      ps.println("\tat " + stes[i].toString());
    }
   
  }

  private static String getRowCommentColumnValue(HSSFRow r) {
    return getCellTextValue(r, SS.COLUMN_ROW_COMMENT, "row comment");
  }
 
  private static String getMarkerColumnValue(HSSFRow r) {
    return getCellTextValue(r, SS.COLUMN_INDEX_MARKER, "marker");
  }
 
  /**
   * @return <code>null</code> if cell is missing, empty or blank
   */
  private static String getCellTextValue(HSSFRow r, int colIndex, String columnName) {
    if(r == null) {
      return null;
    }
    HSSFCell cell = r.getCell((short) colIndex);
    if(cell == null) {
      return null;
    }
    if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
      return null;
    }
    if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
      return cell.getRichStringCellValue().getString();
    }
   
    throw new RuntimeException("Bad cell type for '" + columnName + "' column: ("
        + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")");
  }
}
TOP

Related Classes of org.apache.poi.hssf.record.formula.functions.TestLookupFunctionsFromSpreadsheet$SS

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
nts)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');