### Question:
Variables implements IVariables { @Override public String fieldSubstitute( String aString, IRowMeta rowMeta, Object[] rowData ) throws HopValueException { if ( aString == null || aString.length() == 0 ) { return aString; } return StringUtil.substituteField( aString, rowMeta, rowData ); } Variables(); @Override void copyVariablesFrom( IVariables variables ); @Override IVariables getParentVariableSpace(); @Override void setParentVariableSpace( IVariables parent ); @Override String getVariable( String variableName, String defaultValue ); @Override String getVariable( String variableName ); @Override boolean getBooleanValueOfVariable( String variableName, boolean defaultValue ); @Override void initializeVariablesFrom( IVariables parent ); @Override String[] listVariables(); @Override synchronized void setVariable( String variableName, String variableValue ); @Override synchronized String environmentSubstitute( String aString ); @Override String fieldSubstitute( String aString, IRowMeta rowMeta, Object[] rowData ); @Override String[] environmentSubstitute( String[] string ); @Override void shareVariablesWith( IVariables variables ); @Override void injectVariables( Map<String, String> prop ); static synchronized IVariables getADefaultVariableSpace();  }### Answer:
@Test public void testFieldSubstitution() throws HopValueException { Object[] rowData = new Object[] { "DataOne", "DataTwo" }; RowMeta rm = new RowMeta(); rm.addValueMeta( new ValueMetaString( "FieldOne" ) ); rm.addValueMeta( new ValueMetaString( "FieldTwo" ) ); Variables vars = new Variables(); assertNull( vars.fieldSubstitute( null, rm, rowData ) ); assertEquals( "", vars.fieldSubstitute( "", rm, rowData ) ); assertEquals( "DataOne", vars.fieldSubstitute( "?{FieldOne}", rm, rowData ) ); assertEquals( "TheDataOne", vars.fieldSubstitute( "The?{FieldOne}", rm, rowData ) ); }