mattcasters commented on code in PR #8823:
URL: https://github.com/apache/hop/pull/8823#discussion_r4246745110


##########
plugins/transforms/javascript/src/test/java/org/apache/hop/pipeline/transforms/javascript/ScriptValuesTest.java:
##########
@@ -236,6 +236,78 @@ void undefinedFieldBecomesNull() throws Exception {
     assertEquals(0, transform.getErrors());
   }
 
+  /**
+   * A replaced field the script does not assign keeps its input value. It 
used to depend on whether
+   * the field name appeared in the script text, so adding or removing a 
comment changed the output.
+   */
+  @Test
+  void replacedFieldNotSetByScriptKeepsInputValue() throws Exception {
+    for (String script : new String[] {"var other = 0;", "//var test_int = 
0;\nvar other = 0;"}) {

Review Comment:
   **[suggestion]** `replacedFieldNotSetByScriptKeepsInputValue` claims the 
comment and no-comment scripts are equivalent, but both use the string `"1"`, 
which `Context.toObject` round-trips, so the comment iteration passes on the 
pre-fix code and never executes the new branch (`test_int` is bound because the 
comment contains the name). `replacedFieldNotSetByScriptIsConvertedToItsType` 
only converts the string `"1"` with the name absent, so it cannot catch the 
Number-to-Integer rounding split above. The integration pipeline 
`0087-javascript-replaced-field-8724.hpl` has the same hole for `test_int`: the 
script is `//var test_int = 0;` plus `var doubled = id * 2;`, so `test_int` 
stays on the old bound path and the golden rows (10, 20, 30) would match before 
this change. The pipeline does fail before the fix for `new_value` / 
`other_int` (that name is absent, so `NOT_FOUND` used to null the field). 
Neither test locks "a comment must not change the value" for a type that does 
not survive
  `Context.toObject`.
   
   **Suggestion:** Keep the string and rename cases, and add one unit test that 
runs the same replaced field twice (name absent, and name present only inside a 
comment) for a BigNumber or Boolean and for a type change whose `convertData` 
result differs from `convertFromJs`. In the integration pipeline, add a 
replaced field whose name does not occur anywhere in the script text, not only 
a rename onto a different input field.



##########
plugins/transforms/javascript/src/main/java/org/apache/hop/pipeline/transforms/javascript/ScriptValues.java:
##########
@@ -303,6 +303,19 @@ private void addValuesToContext(IRowMeta rowMeta, Object[] 
row) throws HopExcept
         for (int i = 0; i < meta.getScriptFields().size(); i++) {
           ScriptValuesMeta.ScriptField field = meta.getScriptFields().get(i);
           Object result = data.scope.get(field.getName(), data.scope);
+          if (result == Scriptable.NOT_FOUND && data.replaceIndex[i] >= 0) {

Review Comment:
   **[bug]** `result == Scriptable.NOT_FOUND` is not "the script did not assign 
this field." `determineUsedFields` treats any substring of the transform script 
as a used field, comments included, and `addFieldsToScope` then does 
`scope.put(name, Context.toObject(value))` before the script runs. 
`Context.toObject` wraps the value: every `Number` (Long, Double, BigDecimal) 
becomes a `NativeNumber` of `doubleValue()`, and a Boolean becomes a 
`NativeBoolean`. After the script, `scope.get` returns that wrapper, the new 
branch is skipped, and `getValueFromJScript` converts the wrapper. A real 
assignment still works, because it replaces the scope property, but a 
comment-only (or read-but-not-assigned) name does not keep the input value. 
Concrete differences versus the `NOT_FOUND` path: a BigNumber or a Long outside 
the 53-bit mantissa is rounded to double; a Boolean is left as a 
`NativeBoolean`, and `ValueMetaBase.getBoolean` then does `(Boolean) object` 
and throws ClassCastException; a Num
 ber such as 10.5 replaced as Integer is truncated by `longValue()` (10) on the 
comment path and `Math.round` (11) on the `convertData` path. Removing the 
comment in issue #8724 therefore still changes the output for those values. The 
guard also ignores an explicit `undefined` only when the name was not injected; 
that part is fine. Rename-to is unaffected when the script field name is not an 
input field (`new_value` -> `other_int`), because that name is never bound.
   
   **Suggestion:** Before `script.exec`, remember the scope object 
`addFieldsToScope` stored for each replaced field (or `NOT_FOUND` if it stored 
nothing). After exec, if `scope.get` returns that same reference or 
`NOT_FOUND`, the script did not assign the field: keep `outputRow[index]` and, 
when the input and output types differ, 
`outputValueMeta.convertData(inputValueMeta, outputRow[index])`. Do not pass 
the injected wrapper through `convertFromJs`. A script assignment allocates a 
new value, so reference equality still lets an assigned field win, including 
`test_int = null`. Add a regression with and without a comment-only mention for 
a BigDecimal that does not fit in a double, a Boolean, and a Number-to-Integer 
conversion of `x.5`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to