/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2015 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed 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.pentaho.di.trans.steps.formula; import java.math.BigDecimal; import java.math.MathContext; import java.util.ArrayList; import java.util.List; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.pentaho.di.core.KettleEnvironment; import org.pentaho.di.core.RowMetaAndData; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.row.RowMeta; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.core.row.value.ValueMetaBigNumber; import org.pentaho.di.core.row.value.ValueMetaInteger; import org.pentaho.di.core.row.value.ValueMetaNumber; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.TransTestFactory; public class FormulaTest { public static final String stepName = "Formula"; static final String KEY1 = "int_value"; static final String KEY2 = "KEY2"; static final String KEY3 = "KEY3"; static final String[] keys = { KEY1, KEY2 }; @BeforeClass public static void before() throws KettleException { KettleEnvironment.init(); } List<RowMetaAndData> getTestRowMetaAndData( int[] value ) { List<RowMetaAndData> list = new ArrayList<RowMetaAndData>(); Object[] row = new Object[ value.length ]; RowMetaInterface rm = new RowMeta(); for ( int i = 0; i < value.length; i++ ) { rm.addValueMeta( new ValueMetaInteger( keys[ i ] ) ); row[ i ] = new Long( value[ i ] ); } list.add( new RowMetaAndData( rm, row ) ); return list; } List<RowMetaAndData> getTestRowMetaAndData( BigDecimal[] value ) { List<RowMetaAndData> list = new ArrayList<RowMetaAndData>(); Object[] row = new Object[ value.length ]; RowMetaInterface rm = new RowMeta(); for ( int i = 0; i < value.length; i++ ) { rm.addValueMeta( new ValueMetaBigNumber( keys[ i ] ) ); row[ i ] = value[ i ]; } list.add( new RowMetaAndData( rm, row ) ); return list; } List<RowMetaAndData> getTestRowMetaAndData() { List<RowMetaAndData> list = new ArrayList<RowMetaAndData>(); Object[] row = new Object[] { null }; RowMetaInterface rm = new RowMeta(); rm.addValueMeta( new ValueMetaNumber( "n" ) ); list.add( new RowMetaAndData( rm, row ) ); return list; } /** * PDI-7923 - Formula step requires Number value type when could be used Integer. see transf_formula_error.ktr * * @throws KettleException */ @Test public void testValueMetaIntegerConversion() throws KettleException { FormulaMetaFunction function = new FormulaMetaFunction( KEY2, "[int_value]", ValueMetaInterface.TYPE_NUMBER, -1, -1, null ); FormulaMeta meta = new FormulaMeta(); meta.setFormula( new FormulaMetaFunction[] { function } ); TransMeta transMeta = TransTestFactory.generateTestTransformation( null, meta, stepName ); List<RowMetaAndData> inputList = getTestRowMetaAndData( new int[] { 13, 14 } ); List<RowMetaAndData> ret = TransTestFactory.executeTestTransformation( transMeta, TransTestFactory.INJECTOR_STEPNAME, stepName, TransTestFactory.DUMMY_STEPNAME, inputList ); Assert.assertNotNull( "So we have some results", ret ); Assert.assertEquals( "We have one result row", 1, ret.size() ); RowMetaAndData rmd = ret.get( 0 ); ValueMetaInterface resValueMeta = rmd.getValueMeta( 2 ); Assert.assertNotNull( resValueMeta ); Assert.assertEquals( "It was Integer value meta and now it is Number", ValueMetaInterface.TYPE_NUMBER, resValueMeta .getType() ); } /** * PDI-7923 - Formula step requires Number value type when could be used Integer. see * sample-datagrid-truncating-numbers.ktr * * @throws KettleException */ @Test public void testValueMetaTypeNotErased() throws KettleException { FormulaMetaFunction function = new FormulaMetaFunction( KEY2, "max([" + KEY1 + "];[" + KEY2 + "])", ValueMetaInterface.TYPE_BIGNUMBER, -1, -1, null ); // Hope kettle is also uses MathContext correctly everywhere BigDecimal great = new BigDecimal( 999.00002, new MathContext( 7 ) ); BigDecimal less = new BigDecimal( 999.00001, new MathContext( 7 ) ); FormulaMeta meta = new FormulaMeta(); meta.setFormula( new FormulaMetaFunction[] { function } ); TransMeta transMeta = TransTestFactory.generateTestTransformation( null, meta, stepName ); List<RowMetaAndData> inputList = getTestRowMetaAndData( new BigDecimal[] { less, great } ); List<RowMetaAndData> ret = TransTestFactory.executeTestTransformation( transMeta, TransTestFactory.INJECTOR_STEPNAME, stepName, TransTestFactory.DUMMY_STEPNAME, inputList ); Assert.assertNotNull( "So we have some results", ret ); Assert.assertEquals( "We have one result row", 1, ret.size() ); RowMetaAndData rmd = ret.get( 0 ); ValueMetaInterface resValueMeta = rmd.getValueMeta( 2 ); Assert.assertNotNull( resValueMeta ); Assert.assertEquals( "It is still BinDecimal", ValueMetaInterface.TYPE_BIGNUMBER, resValueMeta.getType() ); Assert.assertTrue( "So we have an a row with at least 3 not null objects", rmd.getData().length >= 3 ); Assert.assertEquals( "Grater value is choosen correctly", great, rmd.getData()[ 2 ] ); } @Test public void testNullReturnValueConversion() throws Exception { FormulaMetaFunction function = new FormulaMetaFunction( "if", "IF(ISNA([n]);[n];[n])", ValueMetaInterface.TYPE_NUMBER, -1, -1, null ); FormulaMeta meta = new FormulaMeta(); meta.setFormula( new FormulaMetaFunction[] { function } ); TransMeta transMeta = TransTestFactory.generateTestTransformation( null, meta, stepName ); List<RowMetaAndData> inputList = getTestRowMetaAndData(); try { TransTestFactory.executeTestTransformation( transMeta, TransTestFactory.INJECTOR_STEPNAME, stepName, TransTestFactory.DUMMY_STEPNAME, inputList ); } catch ( KettleException e ) { Assert.fail( "Null is not handled correctly" ); } } }