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 3fe80f3a0a Fix#6980 stream Lookup not saving the link to the data 
source (#6986)
3fe80f3a0a is described below

commit 3fe80f3a0af399f20bb0179fe11bd0145ab279aa
Author: Lance <[email protected]>
AuthorDate: Mon Apr 13 20:20:53 2026 +0800

    Fix#6980 stream Lookup not saving the link to the data source (#6986)
    
    * Fix stream Lookup not saving the link to the data source
    
    Signed-off-by: lance <[email protected]>
    
    * fix hop split on stream lookup
    
    ---------
    
    Signed-off-by: lance <[email protected]>
    Co-authored-by: Hans Van Akelyen <[email protected]>
---
 .../transforms/streamlookup/StreamLookupMeta.java  |  26 +-
 .../streamlookup/StreamLookupMetaTest.java         | 526 +++++++++++++++++++++
 2 files changed, 551 insertions(+), 1 deletion(-)

diff --git 
a/plugins/transforms/streamlookup/src/main/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMeta.java
 
b/plugins/transforms/streamlookup/src/main/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMeta.java
index 5a8fe0ab1e..8e93e083bc 100644
--- 
a/plugins/transforms/streamlookup/src/main/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMeta.java
+++ 
b/plugins/transforms/streamlookup/src/main/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMeta.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.List;
 import lombok.Getter;
 import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.hop.core.CheckResult;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.ICheckResult;
@@ -116,11 +117,34 @@ public class StreamLookupMeta extends 
BaseTransformMeta<StreamLookup, StreamLook
     return new StreamLookupMeta(this);
   }
 
+  /**
+   * Keeps {@link #sourceTransformName} in sync when the lookup info stream is 
repointed from the
+   * canvas (e.g. hop split, detach, drawing the info hop). Without this, 
{@link
+   * #searchInfoAndTargetTransforms} would keep resetting the stream from the 
stale persisted name.
+   */
+  @Override
+  public void handleStreamSelection(IStream stream) {
+    List<IStream> infoStreams = getTransformIOMeta().getInfoStreams();
+    if (infoStreams.isEmpty() || !infoStreams.contains(stream)) {
+      return;
+    }
+    TransformMeta tm = stream.getTransformMeta();
+    if (tm != null) {
+      setSourceTransformName(tm.getName());
+      stream.setSubject(tm.getName());
+    }
+  }
+
   @Override
   public void searchInfoAndTargetTransforms(List<TransformMeta> transforms) {
     List<IStream> infoStreams = getTransformIOMeta().getInfoStreams();
     for (IStream stream : infoStreams) {
-      stream.setTransformMeta(TransformMeta.findTransform(transforms, 
stream.getSubject()));
+      String lookupName = stream.getSubject();
+      if (StringUtils.isNotBlank(sourceTransformName)) {
+        lookupName = sourceTransformName;
+        stream.setSubject(sourceTransformName);
+      }
+      stream.setTransformMeta(TransformMeta.findTransform(transforms, 
Const.trim(lookupName)));
     }
   }
 
diff --git 
a/plugins/transforms/streamlookup/src/test/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMetaTest.java
 
b/plugins/transforms/streamlookup/src/test/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMetaTest.java
index de169c808d..8d36b4c146 100644
--- 
a/plugins/transforms/streamlookup/src/test/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMetaTest.java
+++ 
b/plugins/transforms/streamlookup/src/test/java/org/apache/hop/pipeline/transforms/streamlookup/StreamLookupMetaTest.java
@@ -17,16 +17,40 @@
 package org.apache.hop.pipeline.transforms.streamlookup;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.hop.core.ICheckResult;
+import org.apache.hop.core.exception.HopTransformException;
+import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.RowMetaBuilder;
 import org.apache.hop.core.row.value.ValueMetaPluginType;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.junit.rules.RestoreHopEnvironmentExtension;
+import org.apache.hop.pipeline.transform.ITransformIOMeta;
+import org.apache.hop.pipeline.transform.TransformMeta;
 import org.apache.hop.pipeline.transform.TransformSerializationTestUtil;
+import org.apache.hop.pipeline.transform.stream.IStream;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 
+/** Unit tests for {@link StreamLookupMeta}. */
+@ExtendWith(RestoreHopEnvironmentExtension.class)
 class StreamLookupMetaTest {
+
   @BeforeEach
   void beforeEach() throws Exception {
     ValueMetaPluginType.getInstance().searchPlugins();
@@ -70,4 +94,506 @@ class StreamLookupMetaTest {
     assertEquals("true", v.getValueDefault());
     assertEquals(IValueMeta.TYPE_BOOLEAN, v.getValueDefaultType());
   }
+
+  @Test
+  void constructorInitializesDefaults() {
+    StreamLookupMeta meta = new StreamLookupMeta();
+    assertTrue(meta.isMemoryPreservationActive());
+    assertNotNull(meta.getLookup());
+    assertTrue(meta.getLookup().getMatchKeys().isEmpty());
+    assertTrue(meta.getLookup().getReturnValues().isEmpty());
+  }
+
+  @Test
+  void copyConstructorDeepCopiesLookup() {
+    StreamLookupMeta original = new StreamLookupMeta();
+    original.setSourceTransformName("A");
+    original.setInputSorted(true);
+    original.setUsingSortedList(true);
+    original.setUsingIntegerPair(true);
+    original.setMemoryPreservationActive(false);
+
+    StreamLookupMeta.MatchKey mk = new StreamLookupMeta.MatchKey();
+    mk.setKeyStream("k1");
+    mk.setKeyLookup("lk1");
+    original.getLookup().getMatchKeys().add(mk);
+
+    StreamLookupMeta.ReturnValue rv = new StreamLookupMeta.ReturnValue();
+    rv.setValue("v");
+    rv.setValueName("vn");
+    rv.setValueDefault("d");
+    rv.setValueDefaultType(IValueMeta.TYPE_INTEGER);
+    original.getLookup().getReturnValues().add(rv);
+
+    StreamLookupMeta copy = new StreamLookupMeta(original);
+    assertEquals(original.getSourceTransformName(), 
copy.getSourceTransformName());
+    assertEquals(original.isInputSorted(), copy.isInputSorted());
+    assertEquals(original.isUsingSortedList(), copy.isUsingSortedList());
+    assertEquals(original.isUsingIntegerPair(), copy.isUsingIntegerPair());
+    assertEquals(original.isMemoryPreservationActive(), 
copy.isMemoryPreservationActive());
+
+    assertNotSame(original.getLookup(), copy.getLookup());
+    assertEquals(1, copy.getLookup().getMatchKeys().size());
+    assertEquals("k1", 
copy.getLookup().getMatchKeys().getFirst().getKeyStream());
+    assertEquals(1, copy.getLookup().getReturnValues().size());
+    assertEquals("v", 
copy.getLookup().getReturnValues().getFirst().getValue());
+  }
+
+  @Test
+  void cloneMatchesCopyConstructorSemantics() {
+    StreamLookupMeta meta = new StreamLookupMeta();
+    meta.setSourceTransformName("Src");
+    StreamLookupMeta.MatchKey mk = new StreamLookupMeta.MatchKey();
+    mk.setKeyStream("a");
+    mk.setKeyLookup("b");
+    meta.getLookup().getMatchKeys().add(mk);
+
+    StreamLookupMeta cloned = (StreamLookupMeta) meta.clone();
+    assertNotSame(meta, cloned);
+    assertEquals(meta.getSourceTransformName(), 
cloned.getSourceTransformName());
+    assertNotSame(meta.getLookup(), cloned.getLookup());
+    assertEquals(
+        meta.getLookup().getMatchKeys().getFirst().getKeyStream(),
+        cloned.getLookup().getMatchKeys().getFirst().getKeyStream());
+  }
+
+  @Test
+  void excludeFromRowLayoutVerificationIsTrue() {
+    assertTrue(new StreamLookupMeta().excludeFromRowLayoutVerification());
+  }
+
+  @Test
+  void 
getTransformIOMetaReturnsSameInstanceAndUsesSourceTransformNameAsInitialSubject()
 {
+    StreamLookupMeta meta = new StreamLookupMeta();
+    meta.setSourceTransformName("Lookup source");
+    ITransformIOMeta io1 = meta.getTransformIOMeta();
+    ITransformIOMeta io2 = meta.getTransformIOMeta();
+    assertSame(io1, io2);
+    assertEquals(1, io1.getInfoStreams().size());
+    assertEquals("Lookup source", 
io1.getInfoStreams().getFirst().getSubject());
+  }
+
+  @Test
+  void resetTransformIoMetaDoesNotClearCachedIoMeta() {
+    StreamLookupMeta meta = new StreamLookupMeta();
+    ITransformIOMeta io = meta.getTransformIOMeta();
+    meta.resetTransformIoMeta();
+    assertSame(io, meta.getTransformIOMeta());
+  }
+
+  /** Unit test for {@link StreamLookupMeta#getFields}. */
+  @Nested
+  class GetFieldsTest {
+
+    @Test
+    void withSingleInfoRowCopiesFieldsFromLookupStreamAndRenames() throws 
HopTransformException {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      StreamLookupMeta.ReturnValue rv = new StreamLookupMeta.ReturnValue();
+      rv.setValue("name");
+      rv.setValueName("out_name");
+      rv.setValueDefaultType(IValueMeta.TYPE_STRING);
+      meta.getLookup().getReturnValues().add(rv);
+
+      IRowMeta lookupRow = new RowMetaBuilder().addString("name").build();
+      RowMeta out = new RowMeta();
+      meta.getFields(out, "origin", new IRowMeta[] {lookupRow}, null, new 
Variables(), null);
+
+      assertEquals(1, out.size());
+      assertEquals("out_name", out.getValueMeta(0).getName());
+      assertEquals("origin", out.getValueMeta(0).getOrigin());
+    }
+
+    @Test
+    void withSingleInfoRowThrowsWhenReturnFieldMissingFromLookup() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      StreamLookupMeta.ReturnValue rv = new StreamLookupMeta.ReturnValue();
+      rv.setValue("missing");
+      rv.setValueName("x");
+      rv.setValueDefaultType(IValueMeta.TYPE_STRING);
+      meta.getLookup().getReturnValues().add(rv);
+
+      IRowMeta lookupRow = new RowMetaBuilder().addString("name").build();
+      RowMeta out = new RowMeta();
+      assertThrows(
+          HopTransformException.class,
+          () -> meta.getFields(out, "o", new IRowMeta[] {lookupRow}, null, new 
Variables(), null));
+    }
+
+    @Test
+    void withoutValidInfoCreatesValueMetaFromDefaults() throws 
HopTransformException {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      StreamLookupMeta.ReturnValue rv = new StreamLookupMeta.ReturnValue();
+      rv.setValueName("col");
+      rv.setValueDefaultType(IValueMeta.TYPE_INTEGER);
+      meta.getLookup().getReturnValues().add(rv);
+
+      RowMeta out = new RowMeta();
+      meta.getFields(out, "origin", null, null, new Variables(), null);
+
+      assertEquals(1, out.size());
+      assertEquals("col", out.getValueMeta(0).getName());
+      assertEquals(IValueMeta.TYPE_INTEGER, out.getValueMeta(0).getType());
+      assertEquals("origin", out.getValueMeta(0).getOrigin());
+    }
+
+    @Test
+    void withInfoArrayWrongShapeUsesDefaultValueMetaPath() throws 
HopTransformException {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      StreamLookupMeta.ReturnValue rv = new StreamLookupMeta.ReturnValue();
+      rv.setValueName("only");
+      rv.setValueDefaultType(IValueMeta.TYPE_STRING);
+      meta.getLookup().getReturnValues().add(rv);
+
+      RowMeta out = new RowMeta();
+      IRowMeta[] twoInfos = {
+        new RowMetaBuilder().addString("a").build(), new 
RowMetaBuilder().addString("b").build()
+      };
+      meta.getFields(out, "origin", twoInfos, null, new Variables(), null);
+
+      assertEquals(1, out.size());
+      assertEquals("only", out.getValueMeta(0).getName());
+    }
+  }
+
+  @Nested
+  class CheckTest {
+
+    private StreamLookupMeta metaWithMinimalValidConfig() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("Lookup");
+      meta.searchInfoAndTargetTransforms(List.of(namedTransform("Lookup")));
+
+      StreamLookupMeta.MatchKey mk = new StreamLookupMeta.MatchKey();
+      mk.setKeyStream("id");
+      mk.setKeyLookup("lid");
+      meta.getLookup().getMatchKeys().add(mk);
+
+      StreamLookupMeta.ReturnValue rv = new StreamLookupMeta.ReturnValue();
+      rv.setValue("ret");
+      rv.setValueName("ret_out");
+      rv.setValueDefaultType(IValueMeta.TYPE_STRING);
+      meta.getLookup().getReturnValues().add(rv);
+
+      return meta;
+    }
+
+    @Test
+    void checkAddsErrorWhenPreviousRowIsEmpty() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta prev = new RowMeta();
+      IRowMeta info = new 
RowMetaBuilder().addInteger("lid").addString("ret").build();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"a", "b"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertTrue(countErrors(remarks) >= 1);
+    }
+
+    @Test
+    void checkAddsErrorWhenMatchKeyMissingFromPrevious() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta info = new 
RowMetaBuilder().addInteger("id").addString("name").build();
+      IRowMeta prev = new RowMetaBuilder().addInteger("wrong").build();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"a", "b"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertTrue(countErrors(remarks) >= 1);
+    }
+
+    @Test
+    void checkAddsErrorWhenFewerThanTwoInputHops() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta prev = new RowMetaBuilder().addInteger("id").build();
+      IRowMeta info = new 
RowMetaBuilder().addInteger("lid").addString("ret").build();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"only"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertTrue(countErrors(remarks) >= 1);
+    }
+
+    @Test
+    void checkAddsErrorWhenKeyLookupFieldMissingFromInfoRow() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta prev = new RowMetaBuilder().addInteger("id").build();
+      IRowMeta info = new 
RowMetaBuilder().addInteger("wrong_lid").addString("ret").build();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"a", "b"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertTrue(countErrors(remarks) >= 1);
+    }
+
+    @Test
+    void checkAddsErrorWhenReturnValueFieldMissingFromInfoRow() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta prev = new RowMetaBuilder().addInteger("id").build();
+      IRowMeta info = new 
RowMetaBuilder().addInteger("lid").addString("other").build();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"a", "b"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertTrue(countErrors(remarks) >= 1);
+    }
+
+    @Test
+    void checkNoErrorsWhenConfigurationAndRowsAreConsistent() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta prev = new RowMetaBuilder().addInteger("id").build();
+      IRowMeta info = new 
RowMetaBuilder().addInteger("lid").addString("ret").build();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"a", "b"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertEquals(0, countErrors(remarks));
+    }
+
+    @Test
+    void checkSourceTransformErrorWhenInfoStreamHasNoTransformMeta() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      
meta.getTransformIOMeta().getInfoStreams().getFirst().setTransformMeta(null);
+
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta prev = new RowMetaBuilder().addInteger("id").build();
+      IRowMeta info = new 
RowMetaBuilder().addInteger("lid").addString("ret").build();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"a", "b"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertTrue(countErrors(remarks) >= 1);
+    }
+
+    @Test
+    void checkAddsErrorWhenLookupInfoRowIsEmpty() {
+      StreamLookupMeta meta = metaWithMinimalValidConfig();
+      List<ICheckResult> remarks = new ArrayList<>();
+      IRowMeta prev = new RowMetaBuilder().addInteger("id").build();
+      IRowMeta info = new RowMeta();
+
+      meta.check(
+          remarks,
+          null,
+          new TransformMeta("SL", meta),
+          prev,
+          new String[] {"a", "b"},
+          new String[] {"o"},
+          info,
+          new Variables(),
+          null);
+
+      assertTrue(countErrors(remarks) >= 1);
+    }
+  }
+
+  /** Unit test for {@link StreamLookupMeta#handleStreamSelection}. */
+  @Nested
+  class HandleStreamSelectionTest {
+
+    @Test
+    void updatesSourceTransformNameWhenInfoStreamIsRepointed() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("OldLookup");
+      IStream infoStream = 
meta.getTransformIOMeta().getInfoStreams().getFirst();
+      TransformMeta inserted = namedTransform("InsertedStep");
+      infoStream.setTransformMeta(inserted);
+      infoStream.setSubject("InsertedStep");
+
+      meta.handleStreamSelection(infoStream);
+
+      assertEquals("InsertedStep", meta.getSourceTransformName());
+      assertEquals("InsertedStep", infoStream.getSubject());
+    }
+
+    @Test
+    void searchInfoAfterHandleStreamSelectionKeepsInsertedLookupSource() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("OldLookup");
+      IStream infoStream = 
meta.getTransformIOMeta().getInfoStreams().getFirst();
+      TransformMeta inserted = namedTransform("InsertedStep");
+      infoStream.setTransformMeta(inserted);
+      infoStream.setSubject("InsertedStep");
+      meta.handleStreamSelection(infoStream);
+
+      meta.searchInfoAndTargetTransforms(List.of(inserted, 
namedTransform("Other")));
+
+      assertSame(inserted, infoStream.getTransformMeta());
+      assertEquals("InsertedStep", meta.getSourceTransformName());
+    }
+
+    @Test
+    void ignoresStreamsThatAreNotInfoStreams() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("KeepMe");
+      IStream other = mock(IStream.class);
+      meta.handleStreamSelection(other);
+      assertEquals("KeepMe", meta.getSourceTransformName());
+    }
+  }
+
+  /** Unit test for {@link StreamLookupMeta#searchInfoAndTargetTransforms}. */
+  @Nested
+  class SearchInfoAndTargetTransformsTest {
+
+    @Test
+    void 
resolvesFromSourceTransformNameAndSyncsInfoStreamSubjectWhenStreamSubjectWasStale()
 {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("Data grid");
+      IStream infoStream = 
meta.getTransformIOMeta().getInfoStreams().getFirst();
+      infoStream.setSubject("wrong-or-empty-subject");
+
+      TransformMeta dataGrid = namedTransform("Data grid");
+      meta.searchInfoAndTargetTransforms(List.of(dataGrid));
+
+      assertSame(dataGrid, infoStream.getTransformMeta());
+      assertEquals("Data grid", infoStream.getSubject());
+    }
+
+    @Test
+    void whenSourceTransformNameBlankUsesExistingStreamSubject() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName(null);
+      IStream infoStream = 
meta.getTransformIOMeta().getInfoStreams().getFirst();
+      infoStream.setSubject("Data grid");
+
+      TransformMeta dataGrid = namedTransform("Data grid");
+      meta.searchInfoAndTargetTransforms(List.of(dataGrid));
+
+      assertSame(dataGrid, infoStream.getTransformMeta());
+    }
+
+    @Test
+    void whenSourceTransformNameIsWhitespaceOnlyFallsBackToStreamSubject() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("   ");
+      IStream infoStream = 
meta.getTransformIOMeta().getInfoStreams().getFirst();
+      infoStream.setSubject("Data grid");
+
+      TransformMeta dataGrid = namedTransform("Data grid");
+      meta.searchInfoAndTargetTransforms(List.of(dataGrid));
+
+      assertSame(dataGrid, infoStream.getTransformMeta());
+    }
+
+    @Test
+    void trimsLookupNameWhenResolvingAgainstPipelineTransforms() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("  Data grid  ");
+      meta.searchInfoAndTargetTransforms(List.of(namedTransform("Data grid")));
+
+      IStream infoStream = 
meta.getTransformIOMeta().getInfoStreams().getFirst();
+      assertEquals("  Data grid  ", infoStream.getSubject());
+      assertEquals("Data grid", infoStream.getTransformMeta().getName());
+    }
+
+    @Test
+    void findTransformIsCaseInsensitive() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("data grid");
+      TransformMeta dataGrid = namedTransform("Data grid");
+      meta.searchInfoAndTargetTransforms(List.of(dataGrid));
+
+      assertSame(
+          dataGrid, 
meta.getTransformIOMeta().getInfoStreams().getFirst().getTransformMeta());
+    }
+
+    @Test
+    void setsTransformMetaToNullWhenNoMatchingTransformExists() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("Unknown step");
+      meta.searchInfoAndTargetTransforms(List.of(namedTransform("Add 
constants")));
+
+      
assertNull(meta.getTransformIOMeta().getInfoStreams().getFirst().getTransformMeta());
+    }
+
+    @Test
+    void emptyTransformListYieldsNullTransformMeta() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("Data grid");
+      meta.searchInfoAndTargetTransforms(List.of());
+
+      
assertNull(meta.getTransformIOMeta().getInfoStreams().getFirst().getTransformMeta());
+    }
+
+    @Test
+    void nullTransformListIsHandled() {
+      StreamLookupMeta meta = new StreamLookupMeta();
+      meta.setSourceTransformName("Add constants");
+      meta.searchInfoAndTargetTransforms(null);
+
+      
assertNull(meta.getTransformIOMeta().getInfoStreams().getFirst().getTransformMeta());
+    }
+  }
+
+  private static long countErrors(List<ICheckResult> remarks) {
+    return remarks.stream().filter(r -> r.getType() == 
ICheckResult.TYPE_RESULT_ERROR).count();
+  }
+
+  private static TransformMeta namedTransform(String name) {
+    TransformMeta tm = mock(TransformMeta.class);
+    when(tm.getName()).thenReturn(name);
+    return tm;
+  }
 }

Reply via email to