@Test
  public void testReturnDigitsOnly() throws KettleException {
    RowMeta inputRowMeta = new RowMeta();
    ValueMetaString nameMeta = new ValueMetaString("Name");
    inputRowMeta.addValueMeta(nameMeta);
    ValueMetaString valueMeta = new ValueMetaString("Value");
    inputRowMeta.addValueMeta(valueMeta);

    RowSet inputRowSet =
        smh.getMockInputRowSet(new Object[][] {{"name1", "qwe123asd456zxc"}, {"name2", null}});
    inputRowSet.setRowMeta(inputRowMeta);

    Calculator calculator =
        new Calculator(smh.stepMeta, smh.stepDataInterface, 0, smh.transMeta, smh.trans);
    calculator.getInputRowSets().add(inputRowSet);
    calculator.setInputRowMeta(inputRowMeta);
    calculator.init(smh.initStepMetaInterface, smh.initStepDataInterface);

    CalculatorMeta meta = new CalculatorMeta();
    meta.setCalculation(
        new CalculatorMetaFunction[] {
          new CalculatorMetaFunction(
              "digits",
              CalculatorMetaFunction.CALC_GET_ONLY_DIGITS,
              "Value",
              null,
              null,
              ValueMetaInterface.TYPE_STRING,
              0,
              0,
              false,
              "",
              "",
              "",
              "")
        });

    // Verify output
    try {
      calculator.addRowListener(
          new RowAdapter() {
            @Override
            public void rowWrittenEvent(RowMetaInterface rowMeta, Object[] row)
                throws KettleStepException {
              assertEquals("123456", row[2]);
            }
          });
      calculator.processRow(meta, new CalculatorData());
    } catch (KettleException ke) {
      ke.printStackTrace();
      fail();
    }
  }
  @Test
  public void calculatorShouldClearDataInstance() throws Exception {
    RowMeta inputRowMeta = new RowMeta();
    ValueMetaInteger valueMeta = new ValueMetaInteger("Value");
    inputRowMeta.addValueMeta(valueMeta);

    RowSet inputRowSet = smh.getMockInputRowSet(new Object[] {-1L});
    inputRowSet.setRowMeta(inputRowMeta);

    Calculator calculator =
        new Calculator(smh.stepMeta, smh.stepDataInterface, 0, smh.transMeta, smh.trans);
    calculator.getInputRowSets().add(inputRowSet);
    calculator.setInputRowMeta(inputRowMeta);
    calculator.init(smh.initStepMetaInterface, smh.initStepDataInterface);

    CalculatorMeta meta = new CalculatorMeta();
    meta.setCalculation(
        new CalculatorMetaFunction[] {
          new CalculatorMetaFunction(
              "test",
              CalculatorMetaFunction.CALC_ABS,
              "Value",
              null,
              null,
              ValueMetaInterface.TYPE_STRING,
              0,
              0,
              false,
              "",
              "",
              "",
              "")
        });

    CalculatorData data = new CalculatorData();
    data = spy(data);

    calculator.processRow(meta, data);
    verify(data).getValueMetaFor(eq(valueMeta.getType()), anyString());

    calculator.processRow(meta, data);
    verify(data).clearValuesMetaMapping();
  }
  public void testCalculator1() throws Exception {
    KettleEnvironment.init();

    PluginRegistry registry = PluginRegistry.getInstance();
    //
    // Create a new transformation...
    //
    TransMeta transMeta = new TransMeta();
    transMeta.setName("calculatortest1");

    //
    // create a row generator step...
    //
    String rowGeneratorStepname = "row generator step";
    RowGeneratorMeta rm = new RowGeneratorMeta();

    // Set the information of the row generator.
    String rowGeneratorPid = registry.getPluginId(StepPluginType.class, rm);
    StepMeta rowGeneratorStep = new StepMeta(rowGeneratorPid, rowGeneratorStepname, rm);
    transMeta.addStep(rowGeneratorStep);

    //
    // Generate 1 empty row
    //
    String[] strDummies = {};
    int[] intDummies = {};

    rm.setDefault();
    rm.setFieldName(strDummies);
    rm.setFieldType(strDummies);
    rm.setValue(strDummies);
    rm.setFieldLength(intDummies);
    rm.setFieldPrecision(intDummies);
    rm.setRowLimit("1");
    rm.setFieldFormat(strDummies);
    rm.setGroup(strDummies);
    rm.setDecimal(strDummies);

    //
    // Add calculator step.
    //
    String calculatorStepname1 = "calculator 1";
    CalculatorMeta calc1 = new CalculatorMeta();

    CalculatorMetaFunction[] calculations =
        new CalculatorMetaFunction[] {
          new CalculatorMetaFunction(
              "timestamp1", // fieldName
              CalculatorMetaFunction.CALC_CONSTANT, // calctype
              "1970-01-01 00:00:00.100100", // fieldA
              "", // String fieldB
              "", // String fieldC
              ValueMetaInterface.TYPE_TIMESTAMP, // valueType,
              0, // int valueLength,
              0, // int valuePrecision,
              false, // boolean removedFromResult,
              "", // String conversionMask,
              "", // String decimalSymbol,
              "", // String groupingSymbol,
              "" // String currencySymbol
              ),
          new CalculatorMetaFunction(
              "int1", // fieldName
              CalculatorMetaFunction.CALC_CONSTANT, // calctype
              "1", // fieldA
              "", // String fieldB
              "", // String fieldC
              ValueMetaInterface.TYPE_INTEGER, // valueType,
              0, // int valueLength,
              0, // int valuePrecision,
              false, // boolean removedFromResult,
              "", // String conversionMask,
              "", // String decimalSymbol,
              "", // String groupingSymbol,
              "" // String currencySymbol
              ),
          new CalculatorMetaFunction(
              "timestamp plus 1 day", // fieldName
              CalculatorMetaFunction.CALC_ADD_DAYS, // calctype
              "timestamp1", // fieldA
              "int1", // String fieldB
              "", // String fieldC
              ValueMetaInterface.TYPE_DATE, // valueType,
              0, // int valueLength,
              0, // int valuePrecision,
              false, // boolean removedFromResult,
              "", // String conversionMask,
              "", // String decimalSymbol,
              "", // String groupingSymbol,
              "" // String currencySymbol
              )
        };
    calc1.setCalculation(calculations);
    //
    String calculatorPid1 = registry.getPluginId(StepPluginType.class, calc1);
    StepMeta calcualtorStep1 = new StepMeta(calculatorPid1, calculatorStepname1, calc1);
    transMeta.addStep(calcualtorStep1);

    //
    TransHopMeta hi1 = new TransHopMeta(rowGeneratorStep, calcualtorStep1);
    transMeta.addTransHop(hi1);

    // Now execute the transformation...
    Trans trans = new Trans(transMeta);

    trans.prepareExecution(null);

    StepInterface si = trans.getStepInterface(calculatorStepname1, 0);
    RowStepCollector endRc = new RowStepCollector();
    si.addRowListener(endRc);

    trans.startThreads();
    trans.waitUntilFinished();

    // Now check whether the output is still as we expect.
    List<RowMetaAndData> goldenImageRows = createResultData1();
    List<RowMetaAndData> resultRows1 = endRc.getRowsWritten();
    checkRows(resultRows1, goldenImageRows);
  }
  public void assertRoundGeneral(
      final Object expectedResult,
      final int calcFunction,
      final Number value,
      final Long precision,
      final Long roundingMode,
      final int valueDataType,
      final int functionDataType)
      throws KettleException {

    final String msg =
        getKettleTypeName(valueDataType) + "->" + getKettleTypeName(functionDataType) + " ";

    final RowMeta inputRowMeta = new RowMeta();
    final List<Object> inputValues = new ArrayList<Object>(3);

    final String fieldValue = "Value";
    final ValueMetaInterface valueMeta;
    switch (valueDataType) {
      case ValueMetaInterface.TYPE_BIGNUMBER:
        valueMeta = new ValueMetaBigNumber(fieldValue);
        break;
      case ValueMetaInterface.TYPE_NUMBER:
        valueMeta = new ValueMetaNumber(fieldValue);
        break;
      case ValueMetaInterface.TYPE_INTEGER:
        valueMeta = new ValueMetaInteger(fieldValue);
        break;
      default:
        throw new IllegalArgumentException(
            msg
                + "Unexpected value dataType: "
                + value.getClass().getName()
                + ". Long, Double or BigDecimal expected.");
    }
    inputRowMeta.addValueMeta(valueMeta);
    inputValues.add(value);

    final String fieldPrecision;
    final ValueMetaInteger precisionMeta;
    if (precision == null) {
      fieldPrecision = null;
      precisionMeta = null;
    } else {
      fieldPrecision = "Precision";
      precisionMeta = new ValueMetaInteger(fieldPrecision);
      inputRowMeta.addValueMeta(precisionMeta);
      inputValues.add(precision);
    }

    final String fieldRoundingMode;
    final ValueMetaInteger roundingModeMeta;
    if (roundingMode == null) {
      fieldRoundingMode = null;
      roundingModeMeta = null;
    } else {
      fieldRoundingMode = "RoundingMode";
      roundingModeMeta = new ValueMetaInteger(fieldRoundingMode);
      inputRowMeta.addValueMeta(roundingModeMeta);
      inputValues.add(roundingMode);
    }

    RowSet inputRowSet = smh.getMockInputRowSet(inputValues.toArray());
    inputRowSet.setRowMeta(inputRowMeta);
    final String fieldA =
        inputRowMeta.size() > 0 ? inputRowMeta.getValueMetaList().get(0).getName() : null;
    final String fieldB =
        inputRowMeta.size() > 1 ? inputRowMeta.getValueMetaList().get(1).getName() : null;
    final String fieldC =
        inputRowMeta.size() > 2 ? inputRowMeta.getValueMetaList().get(2).getName() : null;

    final int resultDataType = functionDataType;

    final String fieldResult = "test";
    final int expectedResultRowSize = inputRowMeta.size() + 1;

    Calculator calculator =
        new Calculator(smh.stepMeta, smh.stepDataInterface, 0, smh.transMeta, smh.trans);
    calculator.getInputRowSets().add(inputRowSet);
    calculator.setInputRowMeta(inputRowMeta);
    calculator.init(smh.initStepMetaInterface, smh.initStepDataInterface);

    CalculatorMeta meta = new CalculatorMeta();
    meta.setCalculation(
        new CalculatorMetaFunction[] {
          new CalculatorMetaFunction(
              fieldResult,
              calcFunction,
              fieldA,
              fieldB,
              fieldC,
              resultDataType,
              2,
              0,
              false,
              "",
              "",
              "",
              "")
        });

    // Verify output
    try {
      calculator.addRowListener(
          new RowAdapter() {
            @Override
            public void rowWrittenEvent(RowMetaInterface rowMeta, Object[] row)
                throws KettleStepException {
              assertEquals(msg + " resultRowSize", expectedResultRowSize, rowMeta.size());
              final int fieldResultIndex = rowMeta.size() - 1;
              assertEquals(
                  msg + " fieldResult",
                  fieldResult,
                  rowMeta.getValueMeta(fieldResultIndex).getName());
              assertEquals(msg, expectedResult, row[fieldResultIndex]);
            }
          });
      calculator.processRow(meta, new CalculatorData());
    } catch (KettleException ke) {
      ke.printStackTrace();
      fail(msg + ke.getMessage());
    }
  }