diff --git a/NEW/src/JdeScoping.DataSync/Etl/Transformers/ColumnRenameTransformer.cs b/NEW/src/JdeScoping.DataSync/Etl/Transformers/ColumnRenameTransformer.cs index dba8c3d..127946a 100644 --- a/NEW/src/JdeScoping.DataSync/Etl/Transformers/ColumnRenameTransformer.cs +++ b/NEW/src/JdeScoping.DataSync/Etl/Transformers/ColumnRenameTransformer.cs @@ -30,10 +30,23 @@ public class ColumnRenameTransformer : DataTransformerBase { _outputNames = new string[source.FieldCount]; _nameToOrdinal = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < source.FieldCount; i++) { var originalName = source.GetName(i); - var outputName = _renames.TryGetValue(originalName, out var newName) ? newName : originalName; + var outputName = _renames.TryGetValue(originalName, out var newName) + ? newName + : originalName; + + if (_nameToOrdinal.TryGetValue(outputName, out var existingOrdinal)) + { + var existingOriginal = source.GetName(existingOrdinal); + throw new InvalidOperationException( + $"Column name collision: '{originalName}' → '{outputName}' conflicts with " + + $"'{existingOriginal}' (already at ordinal {existingOrdinal}). " + + $"Each output column name must be unique."); + } + _outputNames[i] = outputName; _nameToOrdinal[outputName] = i; } diff --git a/NEW/tests/JdeScoping.DataSync.Tests/Etl/Transformers/ColumnRenameTransformerTests.cs b/NEW/tests/JdeScoping.DataSync.Tests/Etl/Transformers/ColumnRenameTransformerTests.cs index 1cee1f6..95b411d 100644 --- a/NEW/tests/JdeScoping.DataSync.Tests/Etl/Transformers/ColumnRenameTransformerTests.cs +++ b/NEW/tests/JdeScoping.DataSync.Tests/Etl/Transformers/ColumnRenameTransformerTests.cs @@ -54,6 +54,33 @@ public class ColumnRenameTransformerTests Assert.Equal("Charlie", reader.GetName(2)); } + [Fact] + public void OnInitialize_RenameCollision_ThrowsInvalidOperationException() + { + // Arrange - renaming A to B when B already exists + var transformer = new ColumnRenameTransformer(("A", "B")); + var source = CreateMockReader(new[] { "A", "B", "C" }); + + // Act & Assert + var ex = Assert.Throws(() => + transformer.Transform(source)); + Assert.Contains("A", ex.Message); + Assert.Contains("B", ex.Message); + Assert.Contains("collision", ex.Message.ToLower()); + } + + [Fact] + public void OnInitialize_PreExistingDuplicates_ThrowsInvalidOperationException() + { + // Arrange - source has duplicate column names (case-insensitive) + var transformer = new ColumnRenameTransformer(); + var source = CreateMockReaderWithDuplicates(new[] { "Name", "name" }); + + // Act & Assert + Assert.Throws(() => + transformer.Transform(source)); + } + private static IDataReader CreateMockReader(string[] columns) { var reader = Substitute.For(); @@ -66,4 +93,16 @@ public class ColumnRenameTransformerTests } return reader; } + + private static IDataReader CreateMockReaderWithDuplicates(string[] columns) + { + var reader = Substitute.For(); + reader.FieldCount.Returns(columns.Length); + for (int i = 0; i < columns.Length; i++) + { + var index = i; + reader.GetName(index).Returns(columns[index]); + } + return reader; + } }