This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new b11de73187 rownum not working on text file input, fixes #7255 (#7259)
b11de73187 is described below

commit b11de7318745ebd401396aeb34914b3e55a03be9
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Wed Jun 10 15:05:08 2026 +0200

    rownum not working on text file input, fixes #7255 (#7259)
---
 .../transforms/0040-text-file-input-rownum.hpl     | 327 +++++++++++++++++++++
 .../transforms/files/text-file-input-rownum.txt    |   3 +
 .../transforms/main-0040-text-file-input.hwf       |  77 +++--
 .../fileinput/text/TextFileInputMeta.java          |   4 +-
 .../fileinput/text/TextFileInputUtils.java         |  21 +-
 .../text/TextFileInputContentParsingTest.java      |  95 ++++++
 6 files changed, 495 insertions(+), 32 deletions(-)

diff --git a/integration-tests/transforms/0040-text-file-input-rownum.hpl 
b/integration-tests/transforms/0040-text-file-input-rownum.hpl
new file mode 100644
index 0000000000..24e19133ee
--- /dev/null
+++ b/integration-tests/transforms/0040-text-file-input-rownum.hpl
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+
+-->
+<pipeline>
+  <info>
+    <name>0040-text-file-input-rownum</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Verifies the "Rownum in output" option of Text File Input is 
actually populated</description>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/06/10 12:00:00.000</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/06/10 12:00:00.000</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>Read with rownum</from>
+      <to>Rownum is null?</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Rownum is null?</from>
+      <to>Rownum is null - Abort</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Rownum is null?</from>
+      <to>Sum rownum</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Sum rownum</from>
+      <to>Check totals</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Check totals</from>
+      <to>Success</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Check totals</from>
+      <to>Wrong totals - Abort</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>Read with rownum</name>
+    <type>TextFileInput2</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <accept_filenames>N</accept_filenames>
+    <passing_through_fields>N</passing_through_fields>
+    <accept_field/>
+    <accept_transform_name/>
+    <separator>,</separator>
+    <enclosure>"</enclosure>
+    <enclosure_breaks>N</enclosure_breaks>
+    <escapechar/>
+    <header>N</header>
+    <nr_headerlines>1</nr_headerlines>
+    <footer>N</footer>
+    <nr_footerlines>1</nr_footerlines>
+    <line_wrapped>N</line_wrapped>
+    <nr_wraps>1</nr_wraps>
+    <layout_paged>N</layout_paged>
+    <nr_lines_per_page>80</nr_lines_per_page>
+    <nr_lines_doc_header>0</nr_lines_doc_header>
+    <noempty>Y</noempty>
+    <include>N</include>
+    <include_field/>
+    <rownum>Y</rownum>
+    <rownumByFile>N</rownumByFile>
+    <rownum_field>rownr</rownum_field>
+    <format>mixed</format>
+    <encoding>UTF-8</encoding>
+    <length>Characters</length>
+    <add_to_result_filenames>N</add_to_result_filenames>
+    <file>
+      <name>${PROJECT_HOME}/files/text-file-input-rownum.txt</name>
+      <filemask/>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <include_subfolders>N</include_subfolders>
+      <type>CSV</type>
+      <compression>None</compression>
+    </file>
+    <filters>
+    </filters>
+    <fields>
+      <field>
+        <name>value</name>
+        <type>String</type>
+        <format/>
+        <currency>$</currency>
+        <decimal>.</decimal>
+        <group>,</group>
+        <nullif/>
+        <ifnull/>
+        <position>-1</position>
+        <length>20</length>
+        <precision>-1</precision>
+        <trim_type>none</trim_type>
+        <repeat>N</repeat>
+      </field>
+    </fields>
+    <limit>0</limit>
+    <error_ignored>N</error_ignored>
+    <skip_bad_files>N</skip_bad_files>
+    <file_error_field/>
+    <file_error_message_field/>
+    <error_line_skipped>N</error_line_skipped>
+    <error_count_field/>
+    <error_fields_field/>
+    <error_text_field/>
+    <bad_line_files_destination_directory/>
+    <bad_line_files_extension>warning</bad_line_files_extension>
+    <error_line_files_destination_directory/>
+    <error_line_files_extension>error</error_line_files_extension>
+    <line_number_files_destination_directory/>
+    <line_number_files_extension>line</line_number_files_extension>
+    <date_format_lenient>Y</date_format_lenient>
+    <date_format_locale>en_US</date_format_locale>
+    <attributes/>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Rownum is null?</name>
+    <type>FilterRows</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <send_true_to>Rownum is null - Abort</send_true_to>
+    <send_false_to>Sum rownum</send_false_to>
+    <compare>
+      <condition>
+        <negated>N</negated>
+        <leftvalue>rownr</leftvalue>
+        <function>IS NULL</function>
+        <rightvalue/>
+      </condition>
+    </compare>
+    <attributes/>
+    <GUI>
+      <xloc>288</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Rownum is null - Abort</name>
+    <type>Abort</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <always_log_rows>Y</always_log_rows>
+    <message>Rownum in output is null - the "Rownum in output" option is not 
being populated</message>
+    <row_threshold>0</row_threshold>
+    <attributes/>
+    <GUI>
+      <xloc>288</xloc>
+      <yloc>256</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Sum rownum</name>
+    <type>GroupBy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <all_rows>N</all_rows>
+    <ignore_aggregate>N</ignore_aggregate>
+    <field_ignore/>
+    <directory>${java.io.tmpdir}</directory>
+    <prefix>grp</prefix>
+    <add_linenr>N</add_linenr>
+    <linenr_fieldname/>
+    <give_back_row>N</give_back_row>
+    <group>
+    </group>
+    <fields>
+      <field>
+        <aggregate>sum_rownr</aggregate>
+        <subject>rownr</subject>
+        <type>SUM</type>
+        <valuefield/>
+      </field>
+      <field>
+        <aggregate>num_rows</aggregate>
+        <subject>value</subject>
+        <type>COUNT_ANY</type>
+        <valuefield/>
+      </field>
+    </fields>
+    <attributes/>
+    <GUI>
+      <xloc>448</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Check totals</name>
+    <type>FilterRows</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <send_true_to>Success</send_true_to>
+    <send_false_to>Wrong totals - Abort</send_false_to>
+    <compare>
+      <condition>
+        <negated>N</negated>
+        <leftvalue>sum_rownr</leftvalue>
+        <function>=</function>
+        <rightvalue/>
+        <value>
+          <name>constant</name>
+          <type>Integer</type>
+          <text>6</text>
+          <length>-1</length>
+          <precision>0</precision>
+          <isnull>N</isnull>
+          <mask>####0;-####0</mask>
+        </value>
+      </condition>
+    </compare>
+    <attributes/>
+    <GUI>
+      <xloc>608</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Wrong totals - Abort</name>
+    <type>Abort</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <always_log_rows>Y</always_log_rows>
+    <message>Unexpected rownum totals (expected 3 rows and sum 
1+2+3=6)</message>
+    <row_threshold>0</row_threshold>
+    <attributes/>
+    <GUI>
+      <xloc>608</xloc>
+      <yloc>256</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Success</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>768</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/transforms/files/text-file-input-rownum.txt 
b/integration-tests/transforms/files/text-file-input-rownum.txt
new file mode 100644
index 0000000000..85c30401ce
--- /dev/null
+++ b/integration-tests/transforms/files/text-file-input-rownum.txt
@@ -0,0 +1,3 @@
+alpha
+beta
+gamma
diff --git a/integration-tests/transforms/main-0040-text-file-input.hwf 
b/integration-tests/transforms/main-0040-text-file-input.hwf
index 4c68f4100c..a2491549b5 100644
--- a/integration-tests/transforms/main-0040-text-file-input.hwf
+++ b/integration-tests/transforms/main-0040-text-file-input.hwf
@@ -22,45 +22,71 @@ limitations under the License.
   <name_sync_with_filename>Y</name_sync_with_filename>
   <description/>
   <extended_description/>
-  <workflow_version/>
   <created_user>-</created_user>
-  <created_date>2021/05/31 11:58:41.121</created_date>
   <modified_user>-</modified_user>
+  <created_date>2021/05/31 11:58:41.121</created_date>
   <modified_date>2021/05/31 11:58:41.121</modified_date>
-  <parameters>
-    </parameters>
+  <workflow_version/>
+  <parameters/>
   <actions>
     <action>
-      <name>Start</name>
-      <description/>
-      <type>SPECIAL</type>
-      <attributes/>
       <repeat>N</repeat>
       <schedulerType>0</schedulerType>
       <intervalSeconds>0</intervalSeconds>
       <intervalMinutes>60</intervalMinutes>
-      <hour>12</hour>
-      <minutes>0</minutes>
-      <weekDay>1</weekDay>
       <DayOfMonth>1</DayOfMonth>
-      <parallel>N</parallel>
+      <weekDay>1</weekDay>
+      <minutes>0</minutes>
+      <hour>12</hour>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
       <xloc>128</xloc>
       <yloc>112</yloc>
+      <parallel>N</parallel>
       <attributes_hac/>
     </action>
     <action>
-      <name>Run text-file-input test</name>
-      <description/>
-      <type>RunPipelineTests</type>
-      <attributes/>
       <test_names>
         <test_name>
           <name>0040-text-file-input-utf-bom UNIT</name>
         </test_name>
       </test_names>
+      <name>Run text-file-input test</name>
+      <description/>
+      <type>RunPipelineTests</type>
+      <attributes/>
+      <xloc>336</xloc>
+      <yloc>112</yloc>
       <parallel>N</parallel>
-      <xloc>416</xloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <filename>${PROJECT_HOME}/0040-text-file-input-rownum.hpl</filename>
+      <params_from_previous>N</params_from_previous>
+      <exec_per_row>N</exec_per_row>
+      <clear_rows>N</clear_rows>
+      <clear_files>N</clear_files>
+      <create_parent_folder>N</create_parent_folder>
+      <set_logfile>N</set_logfile>
+      <set_append_logfile>N</set_append_logfile>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <loglevel>Basic</loglevel>
+      <wait_until_finished>Y</wait_until_finished>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <run_configuration>local</run_configuration>
+      <name>0040-text-file-input-rownum.hpl</name>
+      <description/>
+      <type>PIPELINE</type>
+      <attributes/>
+      <xloc>608</xloc>
       <yloc>112</yloc>
+      <parallel>N</parallel>
       <attributes_hac/>
     </action>
   </actions>
@@ -68,18 +94,21 @@ limitations under the License.
     <hop>
       <from>Start</from>
       <to>Run text-file-input test</to>
-      <enabled>Y</enabled>
       <evaluation>Y</evaluation>
       <unconditional>Y</unconditional>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Run text-file-input test</from>
+      <to>0040-text-file-input-rownum.hpl</to>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+      <enabled>Y</enabled>
     </hop>
   </hops>
   <notepads>
     <notepad>
       <note>Test reading CSV files with the CSV Input transform </note>
-      <xloc>128</xloc>
-      <yloc>208</yloc>
-      <width>284</width>
-      <heigth>26</heigth>
       <fontname>Inter</fontname>
       <fontsize>11</fontsize>
       <fontbold>N</fontbold>
@@ -93,6 +122,10 @@ limitations under the License.
       <bordercolorred>14</bordercolorred>
       <bordercolorgreen>58</bordercolorgreen>
       <bordercolorblue>90</bordercolorblue>
+      <xloc>128</xloc>
+      <yloc>208</yloc>
+      <width>284</width>
+      <height>-1</height>
     </notepad>
   </notepads>
   <attributes/>
diff --git 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputMeta.java
 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputMeta.java
index 9347b343ec..4c123242a9 100644
--- 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputMeta.java
+++ 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputMeta.java
@@ -664,12 +664,12 @@ public class TextFileInputMeta
 
   @Override
   public boolean isIncludeFilename() {
-    return false;
+    return content.includeFilename;
   }
 
   @Override
   public boolean isIncludeRowNumber() {
-    return false;
+    return content.includeRowNumber;
   }
 
   public String[] getInfoTransforms() {
diff --git 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputUtils.java
 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputUtils.java
index 53a81d4f43..b9b937112a 100644
--- 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputUtils.java
+++ 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputUtils.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.gui.ITextFileInputField;
@@ -536,42 +537,46 @@ public class TextFileInputUtils {
         }
 
         // Possibly add short filename...
-        if (additionalOutputFields.getShortFilenameField() != null) {
+        // The conditions below must stay in sync with 
TextFileInputMeta.getFields(), which adds
+        // these columns using StringUtils.isNotBlank(...). Using a plain != 
null check here would
+        // populate (and shift) columns that getFields never added when a 
field name is set to an
+        // empty/blank string, misaligning every following additional output 
field.
+        if 
(StringUtils.isNotBlank(additionalOutputFields.getShortFilenameField())) {
           r[index] = shortFilename;
           index++;
         }
         // Add Extension
-        if (additionalOutputFields.getExtensionField() != null) {
+        if 
(StringUtils.isNotBlank(additionalOutputFields.getExtensionField())) {
           r[index] = extension;
           index++;
         }
         // add path
-        if (additionalOutputFields.getPathField() != null) {
+        if (StringUtils.isNotBlank(additionalOutputFields.getPathField())) {
           r[index] = path;
           index++;
         }
         // Add Size
-        if (additionalOutputFields.getSizeField() != null) {
+        if (StringUtils.isNotBlank(additionalOutputFields.getSizeField())) {
           r[index] = size;
           index++;
         }
         // add Hidden
-        if (additionalOutputFields.getHiddenField() != null) {
+        if (StringUtils.isNotBlank(additionalOutputFields.getHiddenField())) {
           r[index] = hidden;
           index++;
         }
         // Add modification date
-        if (additionalOutputFields.getLastModificationField() != null) {
+        if 
(StringUtils.isNotBlank(additionalOutputFields.getLastModificationField())) {
           r[index] = modificationDateTime;
           index++;
         }
         // Add Uri
-        if (additionalOutputFields.getUriField() != null) {
+        if (StringUtils.isNotBlank(additionalOutputFields.getUriField())) {
           r[index] = uri;
           index++;
         }
         // Add RootUri
-        if (additionalOutputFields.getRootUriField() != null) {
+        if (StringUtils.isNotBlank(additionalOutputFields.getRootUriField())) {
           r[index] = rooturi;
           index++;
         }
diff --git 
a/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputContentParsingTest.java
 
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputContentParsingTest.java
index b716979ca4..6335105585 100644
--- 
a/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputContentParsingTest.java
+++ 
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputContentParsingTest.java
@@ -17,6 +17,10 @@
 
 package org.apache.hop.pipeline.transforms.fileinput.text;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import java.util.List;
 import org.apache.hop.core.file.TextFileInputField;
 import org.apache.hop.core.variables.Variables;
@@ -28,6 +32,97 @@ class TextFileInputContentParsingTest extends 
BaseTextParsingTest {
   @RegisterExtension
   static RestoreHopEngineEnvironmentExtension env = new 
RestoreHopEngineEnvironmentExtension();
 
+  /**
+   * Regression guard: the "Rownum in output" option must actually populate 
the row-number column.
+   * It regressed (commit 6bdc5fd095) because 
TextFileInputMeta.isIncludeRowNumber() was stubbed to
+   * return false, so getFields added the column but convertLineToRow never 
filled it (null on every
+   * row).
+   */
+  @Test
+  void testIncludeRowNumberIsPopulated() throws Exception {
+    meta.getContent().setFileFormat("unix");
+    meta.getContent().setIncludeRowNumber(true);
+    meta.getContent().setRowNumberField("rownr");
+
+    initByFile("default.csv");
+    setFields(
+        new TextFileInputField("f1", -1, -1),
+        new TextFileInputField("f2", -1, -1),
+        new TextFileInputField("f3", -1, -1));
+
+    process();
+
+    int idx = data.outputRowMeta.indexOfValue("rownr");
+    assertTrue(idx >= 0, "rownr column should be present");
+    assertEquals(3, rows.size());
+    for (int i = 0; i < rows.size(); i++) {
+      assertNotNull(rows.get(i)[idx], "rownr must not be null on row " + i);
+      assertEquals((long) (i + 1), ((Number) rows.get(i)[idx]).longValue());
+    }
+  }
+
+  /**
+   * Regression guard for the "include filename in output" option, broken the 
same way as rownum
+   * (TextFileInputMeta.isIncludeFilename() was stubbed to return false).
+   */
+  @Test
+  void testIncludeFilenameIsPopulated() throws Exception {
+    meta.getContent().setFileFormat("unix");
+    meta.getContent().setIncludeFilename(true);
+    meta.getContent().setFilenameField("fname");
+
+    initByFile("default.csv");
+    setFields(
+        new TextFileInputField("f1", -1, -1),
+        new TextFileInputField("f2", -1, -1),
+        new TextFileInputField("f3", -1, -1));
+
+    process();
+
+    int idx = data.outputRowMeta.indexOfValue("fname");
+    assertTrue(idx >= 0, "fname column should be present");
+    assertEquals(3, rows.size());
+    for (int i = 0; i < rows.size(); i++) {
+      Object value = rows.get(i)[idx];
+      assertNotNull(value, "filename must not be null on row " + i);
+      assertTrue(value.toString().endsWith("default.csv"), "unexpected 
filename: " + value);
+    }
+  }
+
+  /**
+   * Regression guard for the additional-output-field misalignment: getFields 
adds these columns
+   * with StringUtils.isNotBlank(...) but the runtime used to add/shift them 
with a plain != null
+   * check. An empty-string field name (how the UI serializes an unused field) 
would then be written
+   * by the runtime even though getFields skipped it, shifting every following 
column by one. Here a
+   * blank short-filename field precedes a real extension field, so the 
extension column must hold
+   * the file extension - not the misaligned short filename.
+   */
+  @Test
+  void testBlankAdditionalFieldDoesNotMisalignColumns() throws Exception {
+    meta.getContent().setFileFormat("unix");
+    // Unused field serialized as an empty string (not null), preceding a real 
one.
+    meta.getAdditionalOutputFields().setShortFilenameField("");
+    meta.getAdditionalOutputFields().setExtensionField("theext");
+
+    initByFile("default.csv");
+    setFields(
+        new TextFileInputField("f1", -1, -1),
+        new TextFileInputField("f2", -1, -1),
+        new TextFileInputField("f3", -1, -1));
+
+    process();
+
+    // The blank short-filename field must NOT have produced a column.
+    assertTrue(
+        data.outputRowMeta.indexOfValue("") < 0, "a blank field name must not 
create a column");
+    int idx = data.outputRowMeta.indexOfValue("theext");
+    assertTrue(idx >= 0, "extension column should be present");
+    assertEquals(3, rows.size());
+    for (int i = 0; i < rows.size(); i++) {
+      assertEquals("csv", rows.get(i)[idx], "extension column misaligned on 
row " + i);
+    }
+  }
+
   @Test
   void testDefaultOptions() throws Exception {
 

Reply via email to