/*! ****************************************************************************** * * 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.core.util; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; import org.junit.*; import org.pentaho.di.core.plugins.PluginInterface; import org.pentaho.di.core.plugins.PluginRegistry; import org.pentaho.di.core.plugins.PluginTypeInterface; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.core.row.value.ValueMetaBase; import org.pentaho.di.core.row.value.ValueMetaPluginType; import static org.junit.Assert.*; public class StringEvaluatorTest { @Test public void testSeries1() throws Exception { String[] series1 = new String[] { "Foo", "Bar", "One", "", "Two", "Three", }; StringEvaluator evaluator = new StringEvaluator( false ); for ( String string : series1 ) { evaluator.evaluateString( string ); } assertEquals( evaluator.getCount(), series1.length ); assertEquals( evaluator.getMaxLength(), 5 ); // We expect to find nothing. This means that we have to revert to a String data type. // assertEquals( evaluator.getStringEvaluationResults().size(), 0 ); } @Test public void testSeries2() throws Exception { String[] series2 = new String[] { "2009/12/31 12:34:56", "2010/02/14 23:22:01", }; StringEvaluator evaluator = new StringEvaluator( false ); for ( String string : series2 ) { evaluator.evaluateString( string ); } assertEquals( evaluator.getCount(), series2.length ); assertEquals( evaluator.getMaxLength(), 19 ); StringEvaluationResult result = evaluator.getStringEvaluationResults().get( 0 ); assertEquals( "Not a date detected", result.getConversionMeta().getType(), ValueMetaInterface.TYPE_DATE ); Date minDate = result.getConversionMeta().getDate( result.getMin() ); Date expectedMinDate = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" ).parse( "2009/12/31 12:34:56" ); assertEquals( minDate.getTime(), expectedMinDate.getTime() ); int nrEmpty = result.getNrNull(); assertEquals( nrEmpty, 0 ); assertEquals( evaluator.getValues().size(), series2.length ); } @Test public void testSeries3() throws Exception { String[] series3 = new String[] { "1234,56", "12394,26", "1934,34", "19245,23", "" }; StringEvaluator evaluator = new StringEvaluator( false ); for ( String string : series3 ) { evaluator.evaluateString( string ); } assertEquals( evaluator.getCount(), series3.length ); assertEquals( evaluator.getMaxLength(), 8 ); StringEvaluationResult result = evaluator.getStringEvaluationResults().get( 0 ); assertEquals( "Not a number detected", result.getConversionMeta().getType(), ValueMetaInterface.TYPE_NUMBER ); int nrEmpty = result.getNrNull(); assertEquals( nrEmpty, 1 ); assertEquals( evaluator.getValues().size(), series3.length ); } @Test public void testSeries4() throws Exception { String[] series4 = new String[] { "01234,56 ", " ", "98765,43 ", "12394,26 ", "01934,34 ", "19245,23 ", "00045,67 ", }; StringEvaluator evaluator = new StringEvaluator( true ); for ( String string : series4 ) { evaluator.evaluateString( string ); } assertEquals( evaluator.getCount(), series4.length ); assertEquals( evaluator.getMaxLength(), 13 ); StringEvaluationResult result = evaluator.getStringEvaluationResults().get( 0 ); assertEquals( "Not a number detected", result.getConversionMeta().getType(), ValueMetaInterface.TYPE_NUMBER ); int nrEmpty = result.getNrNull(); assertEquals( nrEmpty, 1 ); assertEquals( evaluator.getValues().size(), series4.length ); } @Test public void testCurrencyData() { StringEvaluator eval = new StringEvaluator( true ); String[] values = new String[] { "$300.00", "$3,400", "$23.00", "($0.50)" }; for ( String value : values ) { eval.evaluateString( value ); } assertEquals( values.length, eval.getCount() ); StringEvaluationResult result = eval.getAdvicedResult(); assertEquals( "Not a number detected", ValueMetaInterface.TYPE_NUMBER, result.getConversionMeta().getType() ); assertEquals( "Precision not correct", 2, result.getConversionMeta().getPrecision() ); assertEquals( "Currency format mask is incorrect", "$#,##0.00;($#,##0.00)", result .getConversionMeta().getConversionMask() ); } @Test public void testCurrencyData_UK() { Locale orig = Locale.getDefault(); try { Locale.setDefault( Locale.UK ); StringEvaluator eval = new StringEvaluator( true ); DecimalFormat currencyFormat = ( (DecimalFormat) NumberFormat.getCurrencyInstance() ); try { currencyFormat.parse( "-£400.059" ); } catch ( ParseException e ) { fail(); } String[] values = new String[] { "£400.019", "£3,400.029", "£23.00", "-£400.059" }; for ( String value : values ) { eval.evaluateString( value ); } assertEquals( values.length, eval.getCount() ); StringEvaluationResult result = eval.getAdvicedResult(); assertEquals( "Not a number detected", ValueMetaInterface.TYPE_NUMBER, result.getConversionMeta().getType() ); assertEquals( "Precision not correct", 2, result.getConversionMeta().getPrecision() ); assertEquals( "Currency format mask is incorrect", "£#,##0.00", result.getConversionMeta().getConversionMask() ); } finally { Locale.setDefault( orig ); } } @Test public void testCustomDateFormats() { List<String> dates = Collections.singletonList( "MM/dd/yyyy" ); List<String> numbers = Collections.singletonList( "#,##0.###" ); StringEvaluator eval = new StringEvaluator( true, numbers, dates ); String[] goodDateValues = new String[] { "01/01/2000", "02/02/2000", "03/03/2000" }; String[] badDateValues = new String[] { "01-01-2000", "02-02-2000", "03-03-2000" }; for ( String value : goodDateValues ) { eval.evaluateString( value ); } assertEquals( goodDateValues.length, eval.getCount() ); StringEvaluationResult result = eval.getAdvicedResult(); assertEquals( "Not a date detected", result.getConversionMeta().getType(), ValueMetaInterface.TYPE_DATE ); eval = new StringEvaluator( true, numbers, dates ); for ( String value : badDateValues ) { eval.evaluateString( value ); } assertEquals( badDateValues.length, eval.getCount() ); result = eval.getAdvicedResult(); assertFalse( "Date detected", result.getConversionMeta().getType() == ValueMetaInterface.TYPE_DATE ); } @Test public void testCustomNumberFormats() { loadValueMetaPlugins(); // Now get to the real testing Locale orig = Locale.getDefault(); try { Locale.setDefault( Locale.US ); StringEvaluator eval = new StringEvaluator(); String[] goodValues = new String[] { "200.00", "999.99", "4,309.88" }; String[] badValues = new String[] { "9 00", "$30.00", "3.999,00" }; for ( String value : goodValues ) { eval.evaluateString( value ); } assertEquals( goodValues.length, eval.getCount() ); StringEvaluationResult result = eval.getAdvicedResult(); assertEquals( "Not a number detected", result.getConversionMeta().getTypeDesc(), "Number" ); eval = new StringEvaluator(); for ( String value : badValues ) { eval.evaluateString( value ); } assertEquals( badValues.length, eval.getCount() ); result = eval.getAdvicedResult(); assertFalse( "Number detected", result.getConversionMeta().getType() == ValueMetaInterface.TYPE_NUMBER ); } finally { Locale.setDefault( orig ); } } @Test public void testDeterminePrecision() { assertEquals( 4, StringEvaluator.determinePrecision( "#.0000" ) ); assertEquals( 4, StringEvaluator.determinePrecision( "0.#### $" ) ); assertEquals( 0, StringEvaluator.determinePrecision( null ) ); assertEquals( 4, StringEvaluator.determinePrecision( "0.##00 $" ) ); assertEquals( 4, StringEvaluator.determinePrecision( "##,##0.#0## $" ) ); } @Test public void testLength_IfEvaluationResultIsNumber() { loadValueMetaPlugins(); StringEvaluator eval = new StringEvaluator(); String[] numbers = new String[] { "1010.10101010", "10.01", "4,309.88" }; for ( String value : numbers ) { eval.evaluateString( value ); } StringEvaluationResult result = eval.getAdvicedResult(); assertEquals( "Number", result.getConversionMeta().getTypeDesc() ); assertEquals( 8, result.getConversionMeta().getPrecision() ); assertEquals( 13, result.getConversionMeta().getLength() ); } private void loadValueMetaPlugins() { // Need to load the ValueMeta plugins PluginRegistry registry = PluginRegistry.getInstance(); assertNotNull( "Registry singleton was not found!", registry ); // Register a new plugin type... // PluginRegistry.addPluginType( ValueMetaPluginType.getInstance() ); // Plugin Registry should initialize without exception Exception initException = null; try { PluginRegistry.init(); } catch ( Exception e ) { initException = e; } assertNull( initException ); // There will always be a PluginRegistryPluginType, so see if we enough plugin types here. // List<Class<? extends PluginTypeInterface>> pluginTypes = registry.getPluginTypes(); assertTrue( "At least two plugin types expected in the registry", pluginTypes.size() > 1 ); // ... and have at least 1 ValueMetaPlugin List<PluginInterface> valueMetaPlugins = registry.getPlugins( ValueMetaPluginType.class ); assertTrue( "Size of plugins list expected to be >1", valueMetaPlugins.size() > 1 ); } @Test public void recognisesNumeric_WhenParenthesesMeanNegative_Integer() throws Exception { String[] samples = { "1,234,567,890", "(1,234,567,890)" }; final Locale environmentLocale = Locale.getDefault(); try { Locale.setDefault( Locale.US ); StringEvaluationResult numericResult = doEvaluation( new StringEvaluator(), samples ); ValueMetaInterface meta = numericResult.getConversionMeta(); assertTrue( Integer.toString( meta.getType() ), ValueMetaBase.isNumeric( meta.getType() ) ); assertEquals( "#,##0.00;(#,##0.00)", meta.getConversionMask() ); } finally { Locale.setDefault( environmentLocale ); } } @Test public void recognisesNumeric_WhenParenthesesMeanNegative_Double() throws Exception { String[] samples = { "1,234,567,890.12", "(1,234,567,890.12)" }; final Locale environmentLocale = Locale.getDefault(); try { Locale.setDefault( Locale.US ); StringEvaluationResult numericResult = doEvaluation( new StringEvaluator(), samples ); ValueMetaInterface meta = numericResult.getConversionMeta(); assertTrue( Integer.toString( meta.getType() ), ValueMetaBase.isNumeric( meta.getType() ) ); assertEquals( "#,##0.00;(#,##0.00)", meta.getConversionMask() ); } finally { Locale.setDefault( environmentLocale ); } } private StringEvaluationResult doEvaluation( StringEvaluator evaluator, String[] samples ) { for ( String sample : samples ) { evaluator.evaluateString( sample ); } assertEquals( evaluator.getCount(), samples.length ); return evaluator.getAdvicedResult(); } }