| /* ==================================================================== |
| 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.formula.functions; |
| |
| import org.apache.poi.ss.SpreadsheetVersion; |
| import org.apache.poi.ss.formula.TwoDEval; |
| import org.apache.poi.ss.formula.eval.AreaEval; |
| import org.apache.poi.ss.formula.eval.AreaEvalBase; |
| import org.apache.poi.ss.formula.eval.NumberEval; |
| import org.apache.poi.ss.formula.eval.RefEval; |
| import org.apache.poi.ss.formula.eval.RefEvalBase; |
| import org.apache.poi.ss.formula.eval.ValueEval; |
| import org.apache.poi.ss.formula.ptg.AreaI; |
| import org.apache.poi.ss.formula.ptg.AreaPtg; |
| import org.apache.poi.ss.formula.ptg.Ref3DPtg; |
| import org.apache.poi.ss.formula.ptg.RefPtg; |
| import org.apache.poi.ss.util.AreaReference; |
| |
| /** |
| * Test helper class for creating mock {@code Eval} objects |
| */ |
| public final class EvalFactory { |
| |
| private EvalFactory() { |
| // no instances of this class |
| } |
| |
| /** |
| * Creates a dummy AreaEval |
| * @param values empty (<code>null</code>) entries in this array will be converted to NumberEval.ZERO |
| */ |
| public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) { |
| AreaPtg areaPtg = new AreaPtg(new AreaReference(areaRefStr, SpreadsheetVersion.EXCEL2007)); |
| return createAreaEval(areaPtg, values); |
| } |
| |
| /** |
| * Creates a dummy AreaEval |
| * @param values empty (<code>null</code>) entries in this array will be converted to NumberEval.ZERO |
| */ |
| public static AreaEval createAreaEval(AreaPtg areaPtg, ValueEval[] values) { |
| int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1; |
| int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1; |
| int nExpected = nRows * nCols; |
| if (values.length != nExpected) { |
| throw new RuntimeException("Expected " + nExpected + " values but got " + values.length); |
| } |
| for (int i = 0; i < nExpected; i++) { |
| if (values[i] == null) { |
| values[i] = NumberEval.ZERO; |
| } |
| } |
| return new MockAreaEval(areaPtg, values); |
| } |
| |
| /** |
| * Creates a single RefEval (with value zero) |
| */ |
| public static RefEval createRefEval(String refStr) { |
| return createRefEval(refStr, NumberEval.ZERO); |
| } |
| public static RefEval createRefEval(String refStr, ValueEval value) { |
| return new MockRefEval(new RefPtg(refStr), value); |
| } |
| |
| private static final class MockAreaEval extends AreaEvalBase { |
| private final ValueEval[] _values; |
| public MockAreaEval(AreaI areaPtg, ValueEval[] values) { |
| super(areaPtg); |
| _values = values; |
| } |
| private MockAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn, ValueEval[] values) { |
| super(firstRow, firstColumn, lastRow, lastColumn); |
| _values = values; |
| } |
| @Override |
| public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) { |
| return getRelativeValue(-1, relativeRowIndex, relativeColumnIndex); |
| } |
| @Override |
| public ValueEval getRelativeValue(int sheetIndex, int relativeRowIndex, int relativeColumnIndex) { |
| if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) { |
| throw new IllegalArgumentException("row index out of range"); |
| } |
| int width = getWidth(); |
| if (relativeColumnIndex < 0 || relativeColumnIndex >=width) { |
| throw new IllegalArgumentException("column index out of range"); |
| } |
| int oneDimensionalIndex = relativeRowIndex * width + relativeColumnIndex; |
| return _values[oneDimensionalIndex]; |
| } |
| @Override |
| public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { |
| if (relFirstRowIx < 0 || relFirstColIx < 0 |
| || relLastRowIx >= getHeight() || relLastColIx >= getWidth()) { |
| throw new RuntimeException("Operation not implemented on this mock object"); |
| } |
| |
| if (relFirstRowIx == 0 && relFirstColIx == 0 |
| && relLastRowIx == getHeight()-1 && relLastColIx == getWidth()-1) { |
| return this; |
| } |
| ValueEval[] values = transpose(_values, getWidth(), relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); |
| return new MockAreaEval(getFirstRow() + relFirstRowIx, getFirstColumn() + relFirstColIx, |
| getFirstRow() + relLastRowIx, getFirstColumn() + relLastColIx, values); |
| } |
| private static ValueEval[] transpose(ValueEval[] srcValues, int srcWidth, |
| int relFirstRowIx, int relLastRowIx, |
| int relFirstColIx, int relLastColIx) { |
| int height = relLastRowIx - relFirstRowIx + 1; |
| int width = relLastColIx - relFirstColIx + 1; |
| ValueEval[] result = new ValueEval[height * width]; |
| for (int r=0; r<height; r++) { |
| int srcRowIx = r + relFirstRowIx; |
| for (int c=0; c<width; c++) { |
| int srcColIx = c + relFirstColIx; |
| int destIx = r * width + c; |
| int srcIx = srcRowIx * srcWidth + srcColIx; |
| result[destIx] = srcValues[srcIx]; |
| } |
| } |
| return result; |
| } |
| @Override |
| public TwoDEval getRow(int rowIndex) { |
| if (rowIndex >= getHeight()) { |
| throw new IllegalArgumentException("Invalid rowIndex " + rowIndex |
| + ". Allowable range is (0.." + getHeight() + ")."); |
| } |
| ValueEval[] values = new ValueEval[getWidth()]; |
| for (int i = 0; i < values.length; i++) { |
| values[i] = getRelativeValue(rowIndex, i); |
| } |
| return new MockAreaEval(rowIndex, getFirstColumn(), rowIndex, getLastColumn(), values); |
| } |
| @Override |
| public TwoDEval getColumn(int columnIndex) { |
| if (columnIndex >= getWidth()) { |
| throw new IllegalArgumentException("Invalid columnIndex " + columnIndex |
| + ". Allowable range is (0.." + getWidth() + ")."); |
| } |
| ValueEval[] values = new ValueEval[getHeight()]; |
| for (int i = 0; i < values.length; i++) { |
| values[i] = getRelativeValue(i, columnIndex); |
| } |
| return new MockAreaEval(getFirstRow(), columnIndex, getLastRow(), columnIndex, values); |
| } |
| } |
| |
| private static final class MockRefEval extends RefEvalBase { |
| private final ValueEval _value; |
| public MockRefEval(RefPtg ptg, ValueEval value) { |
| super(-1, -1, ptg.getRow(), ptg.getColumn()); |
| _value = value; |
| } |
| public MockRefEval(Ref3DPtg ptg, ValueEval value) { |
| super(-1, -1, ptg.getRow(), ptg.getColumn()); |
| _value = value; |
| } |
| @Override |
| public ValueEval getInnerValueEval(int sheetIndex) { |
| return _value; |
| } |
| @Override |
| public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { |
| throw new RuntimeException("Operation not implemented on this mock object"); |
| } |
| } |
| } |