void readSourceValuesFromInfoSteps() throws KettleStepException {
    Map<String, Integer> inputStepWasProcessed = new HashMap<>();
    for ( int i = 0; i < meta.getValidations().size(); i++ ) {
      Validation field = meta.getValidations().get( i );
      List<StreamInterface> streams = meta.getStepIOMeta().getInfoStreams();

      // If we need to source the allowed values data from a different step, we do this here as well
      //
      if ( field.isSourcingValues() ) {
        if ( streams.get( i ).getStepMeta() == null ) {
          throw new KettleStepException(
            "There is no valid source step specified for the allowed values of validation ["
              + field.getName() + "]" );
        }
        if ( Utils.isEmpty( field.getSourcingField() ) ) {
          throw new KettleStepException(
            "There is no valid source field specified for the allowed values of validation ["
              + field.getName() + "]" );
        }

        // Still here : OK, read the data from the specified step...
        // The data is stored in data.listValues[i] and data.constantsMeta
        //
        String stepName = streams.get( i ).getStepname();
        if ( inputStepWasProcessed.containsKey( stepName ) ) {
          // step was processed for other StreamInterface
          data.listValues[ i ] = data.listValues[ inputStepWasProcessed.get( stepName ) ];
          data.constantsMeta[ i ] = data.constantsMeta[ inputStepWasProcessed.get( stepName ) ];
          continue;
        }
        RowSet allowedRowSet = findInputRowSet( stepName );
        int fieldIndex = -1;
        List<Object> allowedValues = new ArrayList<Object>();
        Object[] allowedRowData = getRowFrom( allowedRowSet );
        while ( allowedRowData != null ) {
          RowMetaInterface allowedRowMeta = allowedRowSet.getRowMeta();
          if ( fieldIndex < 0 ) {
            fieldIndex = allowedRowMeta.indexOfValue( field.getSourcingField() );
            if ( fieldIndex < 0 ) {
              throw new KettleStepException( "Source field ["
                + field.getSourcingField() + "] is not found in the source row data" );
            }
            data.constantsMeta[ i ] = allowedRowMeta.getValueMeta( fieldIndex );
          }
          Object allowedValue = allowedRowData[ fieldIndex ];
          if ( allowedValue != null ) {
            allowedValues.add( allowedValue );
          }

          // Grab another row too...
          //
          allowedRowData = getRowFrom( allowedRowSet );
        }
        // Set the list values in the data block...
        //
        data.listValues[ i ] = allowedValues.toArray( new Object[ allowedValues.size() ] );
        inputStepWasProcessed.put( stepName, i );
      }
    }
  }
@Test
  public void readSourceValuesFromInfoStepsTest() throws Exception {
    String name = "Valid list";
    String field = "sourcing field 1";
    String values = "A";
    mockHelper.stepMeta.setName( name );
    ValidatorMeta meta = new ValidatorMeta();
    List<Validation> validations = new ArrayList<>();
    Validation validation1 = new Validation( "validation1" );
    validation1.setSourcingValues( true );
    validation1.setSourcingField( field );
    validations.add( validation1 );

    Validation validation2 = new Validation( "validation2" );
    validation2.setSourcingValues( true );
    validation2.setSourcingField( "sourcing field 2" );
    validations.add( validation2 );

    meta.setValidations( validations );

    StepMeta stepMeta = new StepMeta();
    stepMeta.setName( name );

    RowSet rowSet = Mockito.mock( RowSet.class );
    Mockito.when( rowSet.getOriginStepName() ).thenReturn( name );
    Mockito.when( rowSet.getDestinationStepName() ).thenReturn( "Validator" );
    Mockito.when( rowSet.getOriginStepCopy() ).thenReturn( 0 );
    Mockito.when( rowSet.getDestinationStepCopy() ).thenReturn( 0 );
    Mockito.when( rowSet.getRow() ).thenReturn( new String[] { values } ).thenReturn( null );
    Mockito.when( rowSet.isDone() ).thenReturn( true );
    RowMetaInterface allowedRowMeta = Mockito.mock( RowMetaInterface.class );
    Mockito.when( rowSet.getRowMeta() ).thenReturn( allowedRowMeta );
    Mockito.when( rowSet.getRowMeta() ).thenReturn( Mockito.mock( RowMetaInterface.class ) );
    Mockito.when( allowedRowMeta.indexOfValue( field ) ).thenReturn( 0 );
    Mockito.when( allowedRowMeta.getValueMeta( 0 ) ).thenReturn( Mockito.mock( ValueMetaInterface.class ) );

    List<RowSet> rowSets = new ArrayList<>();
    rowSets.add( rowSet );
    validator.setInputRowSets( rowSets );
    mockHelper.transMeta.setStep( 0, stepMeta );
    Mockito.when( mockHelper.transMeta.findStep( Mockito.eq( name ) ) ).thenReturn( stepMeta );

    StepMeta stepMetaValidList = new StepMeta();
    stepMetaValidList.setName( name );

    meta.getStepIOMeta().getInfoStreams().get( 0 ).setStepMeta( stepMetaValidList );
    meta.getStepIOMeta().getInfoStreams().get( 1 ).setStepMeta( stepMetaValidList );
    Class<?> validatorClass = Validator.class;
    Field metaField = validatorClass.getDeclaredField( "meta" );
    metaField.setAccessible( true );
    metaField.set( validator, meta );

    ValidatorData data = new ValidatorData();
    data.constantsMeta = new ValueMetaInterface[ 2 ];
    Field dataField = validatorClass.getDeclaredField( "data" );
    dataField.setAccessible( true );
    dataField.set( validator, data );
    data.listValues = new Object[ 2 ][ 2 ];

    validator.readSourceValuesFromInfoSteps();

    Assert.assertEquals( values, data.listValues[ 0 ][ 0 ] );
    Assert.assertEquals( values, data.listValues[ 1 ][ 0 ] );
  }