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 b82cbee8fa Fix #6144 the outputValue initialization issue in the 
Formula transform (#6158)
b82cbee8fa is described below

commit b82cbee8fa2a324b98ed1c0128a110e205d4654e
Author: lance <[email protected]>
AuthorDate: Tue Dec 23 21:48:26 2025 +0800

    Fix #6144 the outputValue initialization issue in the Formula transform 
(#6158)
    
    * Fix the outputValue initialization issue in the Formula transform
    
    Signed-off-by: lance <[email protected]>
    
    * add formula error type,integration-tests
    
    Signed-off-by: lance <[email protected]>
    
    * Add test to workflow
    
    ---------
    
    Signed-off-by: lance <[email protected]>
    Co-authored-by: Hans Van Akelyen <[email protected]>
---
 .../transforms/0042-formula-logical-error.hpl      | 211 +++++++++++++++++++++
 .../datasets/golden-formula-logical-error.csv      |   3 +
 .../transforms/main-0042-formula-logical.hwf       |  14 +-
 .../dataset/golden-formula-logical-error.json      |  48 +++++
 .../unit-test/0042-formula-logical-error UNIT.json |  48 +++++
 .../hop/pipeline/transforms/formula/Formula.java   |   4 +-
 .../pipeline/transforms/formula/FormulaTests.java  |  95 ++++++++++
 7 files changed, 415 insertions(+), 8 deletions(-)

diff --git a/integration-tests/transforms/0042-formula-logical-error.hpl 
b/integration-tests/transforms/0042-formula-logical-error.hpl
new file mode 100644
index 0000000000..74e9168323
--- /dev/null
+++ b/integration-tests/transforms/0042-formula-logical-error.hpl
@@ -0,0 +1,211 @@
+<?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>0042-formula-logical-error</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <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>2025/12/04 00:09:25.633</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2025/12/04 00:09:25.633</modified_date>
+  </info>
+  <notepads>
+    <notepad>
+      <backgroundcolorblue>251</backgroundcolorblue>
+      <backgroundcolorgreen>232</backgroundcolorgreen>
+      <backgroundcolorred>201</backgroundcolorred>
+      <bordercolorblue>90</bordercolorblue>
+      <bordercolorgreen>58</bordercolorgreen>
+      <bordercolorred>14</bordercolorred>
+      <fontbold>N</fontbold>
+      <fontcolorblue>90</fontcolorblue>
+      <fontcolorgreen>58</fontcolorgreen>
+      <fontcolorred>14</fontcolorred>
+      <fontitalic>N</fontitalic>
+      <fontname>Microsoft YaHei UI</fontname>
+      <fontsize>9</fontsize>
+      <height>24</height>
+      <xloc>64</xloc>
+      <yloc>256</yloc>
+      <note>The formula IF([card] > 0, [card], NA()) fails because NA() is not 
convertible to an integer type.</note>
+      <width>503</width>
+    </notepad>
+  </notepads>
+  <order>
+    <hop>
+      <from>card</from>
+      <to>privacy and card and size</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>privacy and card and size</from>
+      <to>verify</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>card</name>
+    <type>DataGrid</type>
+    <description/>
+    <distribute>N</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <data>
+      <line>
+        <item>29</item>
+        <item/>
+        <item/>
+      </line>
+      <line>
+        <item>0</item>
+        <item>J</item>
+        <item>133181722624</item>
+      </line>
+    </data>
+    <fields>
+      <field>
+        <length>-1</length>
+        <precision>-1</precision>
+        <currency/>
+        <set_empty_string>N</set_empty_string>
+        <name>card</name>
+        <format/>
+        <group/>
+        <decimal/>
+        <type>Integer</type>
+      </field>
+      <field>
+        <length>-1</length>
+        <precision>-1</precision>
+        <currency/>
+        <set_empty_string>N</set_empty_string>
+        <name>privacy</name>
+        <format/>
+        <group/>
+        <decimal/>
+        <type>String</type>
+      </field>
+      <field>
+        <length>-1</length>
+        <precision>-1</precision>
+        <currency/>
+        <set_empty_string>N</set_empty_string>
+        <name>size</name>
+        <format/>
+        <group/>
+        <decimal/>
+        <type>Integer</type>
+      </field>
+    </fields>
+    <attributes/>
+    <GUI>
+      <xloc>112</xloc>
+      <yloc>160</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>privacy and card and size</name>
+    <type>Formula</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <formulas>
+      <formula>
+        <field_name>privacy</field_name>
+        <formula>IF(isNA([privacy]), "N", [privacy])</formula>
+        <replace_field>privacy</replace_field>
+        <set_na>N</set_na>
+        <value_length>-1</value_length>
+        <value_precision>-1</value_precision>
+        <value_type>2</value_type>
+      </formula>
+      <formula>
+        <field_name>card</field_name>
+        <formula>IF([card] > 0, [card], NA())</formula>
+        <replace_field>card</replace_field>
+        <set_na>N</set_na>
+        <value_length>-1</value_length>
+        <value_precision>-1</value_precision>
+        <value_type>5</value_type>
+      </formula>
+      <formula>
+        <field_name>size_m</field_name>
+        <formula>([size]/1024/1024)</formula>
+        <replace_field/>
+        <set_na>N</set_na>
+        <value_length>-1</value_length>
+        <value_precision>-1</value_precision>
+        <value_type>5</value_type>
+      </formula>
+      <formula>
+        <field_name>size_g</field_name>
+        <formula>([size]/1024/1024/1024)</formula>
+        <replace_field/>
+        <set_na>N</set_na>
+        <value_length>-1</value_length>
+        <value_precision>-1</value_precision>
+        <value_type>5</value_type>
+      </formula>
+    </formulas>
+    <attributes/>
+    <GUI>
+      <xloc>256</xloc>
+      <yloc>160</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>verify</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>400</xloc>
+      <yloc>160</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git 
a/integration-tests/transforms/datasets/golden-formula-logical-error.csv 
b/integration-tests/transforms/datasets/golden-formula-logical-error.csv
new file mode 100644
index 0000000000..ffc952b7eb
--- /dev/null
+++ b/integration-tests/transforms/datasets/golden-formula-logical-error.csv
@@ -0,0 +1,3 @@
+card,privacy,size,size_m,size_g
+29,,,0,0
+,J,133181722624,127012,124
diff --git a/integration-tests/transforms/main-0042-formula-logical.hwf 
b/integration-tests/transforms/main-0042-formula-logical.hwf
index 7b9b47cd1f..5779e72fb5 100644
--- a/integration-tests/transforms/main-0042-formula-logical.hwf
+++ b/integration-tests/transforms/main-0042-formula-logical.hwf
@@ -35,14 +35,15 @@ limitations under the License.
       <description/>
       <type>SPECIAL</type>
       <attributes/>
-      <repeat>N</repeat>
-      <schedulerType>0</schedulerType>
-      <intervalSeconds>0</intervalSeconds>
-      <intervalMinutes>60</intervalMinutes>
+      <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
       <hour>12</hour>
+      <intervalMinutes>60</intervalMinutes>
+      <intervalSeconds>0</intervalSeconds>
       <minutes>0</minutes>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
       <weekDay>1</weekDay>
-      <DayOfMonth>1</DayOfMonth>
       <parallel>N</parallel>
       <xloc>50</xloc>
       <yloc>50</yloc>
@@ -57,6 +58,9 @@ limitations under the License.
         <test_name>
           <name>0042-formula-logical UNIT</name>
         </test_name>
+        <test_name>
+          <name>0042-formula-logical-error UNIT</name>
+        </test_name>
       </test_names>
       <parallel>N</parallel>
       <xloc>192</xloc>
diff --git 
a/integration-tests/transforms/metadata/dataset/golden-formula-logical-error.json
 
b/integration-tests/transforms/metadata/dataset/golden-formula-logical-error.json
new file mode 100644
index 0000000000..5375bbe713
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/dataset/golden-formula-logical-error.json
@@ -0,0 +1,48 @@
+{
+  "base_filename": "golden-formula-logical-error.csv",
+  "name": "golden-formula-logical-error",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "card",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "privacy",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "size",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "size_m",
+      "field_format": "####0;-####0"
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 5,
+      "field_precision": 0,
+      "field_name": "size_g",
+      "field_format": "####0;-####0"
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git 
a/integration-tests/transforms/metadata/unit-test/0042-formula-logical-error 
UNIT.json 
b/integration-tests/transforms/metadata/unit-test/0042-formula-logical-error 
UNIT.json
new file mode 100644
index 0000000000..9db3617d0f
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/unit-test/0042-formula-logical-error 
UNIT.json      
@@ -0,0 +1,48 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "card",
+          "data_set_field": "card"
+        },
+        {
+          "transform_field": "privacy",
+          "data_set_field": "privacy"
+        },
+        {
+          "transform_field": "size",
+          "data_set_field": "size"
+        },
+        {
+          "transform_field": "size_m",
+          "data_set_field": "size_m"
+        },
+        {
+          "transform_field": "size_g",
+          "data_set_field": "size_g"
+        }
+      ],
+      "field_order": [
+        "card",
+        "privacy",
+        "size",
+        "size_m",
+        "size_g"
+      ],
+      "data_set_name": "golden-formula-logical-error",
+      "transform_name": "verify"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0042-formula-logical-error UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0042-formula-logical-error.hpl"
+}
\ No newline at end of file
diff --git 
a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/Formula.java
 
b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/Formula.java
index d1eb7454c7..7318ff657a 100644
--- 
a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/Formula.java
+++ 
b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/Formula.java
@@ -139,10 +139,8 @@ public class Formula extends BaseTransform<FormulaMeta, 
FormulaData> {
     }
 
     Object[] outputRowData = RowDataUtil.resizeArray(r, 
data.outputRowMeta.size());
-    Object outputValue = null;
-
     for (int i = 0; i < meta.getFormulas().size(); i++) {
-
+      Object outputValue = null;
       FormulaMetaFunction formula = meta.getFormulas().get(i);
       FormulaParser parser =
           new FormulaParser(
diff --git 
a/plugins/transforms/formula/src/test/java/org/apache/hop/pipeline/transforms/formula/FormulaTests.java
 
b/plugins/transforms/formula/src/test/java/org/apache/hop/pipeline/transforms/formula/FormulaTests.java
new file mode 100644
index 0000000000..0529284588
--- /dev/null
+++ 
b/plugins/transforms/formula/src/test/java/org/apache/hop/pipeline/transforms/formula/FormulaTests.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+package org.apache.hop.pipeline.transforms.formula;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import org.apache.hop.core.logging.ILoggingObject;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaInteger;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.pipeline.PipelineTestingUtil;
+import org.apache.hop.pipeline.transforms.mock.TransformMockHelper;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/** Unit test for {@link Formula} */
+class FormulaTests {
+  private TransformMockHelper<FormulaMeta, FormulaData> transformMockHelper;
+
+  @BeforeEach
+  void setUp() {
+    transformMockHelper =
+        new TransformMockHelper<>("Formula", FormulaMeta.class, 
FormulaData.class);
+    when(transformMockHelper.logChannelFactory.create(any(), 
any(ILoggingObject.class)))
+        .thenReturn(transformMockHelper.iLogChannel);
+    when(transformMockHelper.pipeline.isRunning()).thenReturn(true);
+    when(transformMockHelper.transformMeta.getName()).thenReturn("Formula");
+  }
+
+  @Test
+  void processRow() throws Exception {
+    Formula formula =
+        new Formula(
+            transformMockHelper.transformMeta,
+            transformMockHelper.iTransformMeta,
+            transformMockHelper.iTransformData,
+            0,
+            transformMockHelper.pipelineMeta,
+            transformMockHelper.pipeline);
+
+    // init success.
+    boolean result = formula.init();
+    assertTrue(result);
+
+    // Set up input row meta
+    RowMeta inputRowMeta = new RowMeta();
+    inputRowMeta.addValueMeta(new ValueMetaInteger("Card"));
+    inputRowMeta.addValueMeta(new ValueMetaString("Privacy"));
+    formula.setInputRowMeta(inputRowMeta);
+
+    // spy
+    formula = spy(formula);
+    doReturn(new Object[] {29, null})
+        .doReturn(new Object[] {0, "Bob"})
+        .doReturn(null)
+        .when(formula)
+        .getRow();
+
+    List<Object[]> execCount = PipelineTestingUtil.execute(formula, 2, false);
+    assertEquals(2, execCount.size());
+
+    IRowMeta outputRowMeta = transformMockHelper.iTransformData.outputRowMeta;
+    assertEquals(2, outputRowMeta.size());
+
+    formula.dispose();
+  }
+
+  @AfterEach
+  void tearDown() {
+    transformMockHelper.cleanUp();
+  }
+}

Reply via email to