using ZB.MOM.WW.ScadaBridge.Commons.Types; namespace ZB.MOM.WW.ScadaBridge.Commons.Tests; public class OverrideCsvParserTests { [Fact] public void Parse_SimpleThreeColumnFile_ReturnsTwoRowsNoErrors() { const string csv = "AttributeName,Value,ElementType\nSetpoint,42,Int32\nName,Pump A,\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); Assert.Equal(2, result.Rows.Count); Assert.Equal("Setpoint", result.Rows[0].AttributeName); Assert.Equal("42", result.Rows[0].Value); Assert.Equal("Int32", result.Rows[0].ElementType); Assert.Equal(2, result.Rows[0].LineNumber); Assert.Equal("Name", result.Rows[1].AttributeName); Assert.Equal("Pump A", result.Rows[1].Value); Assert.Null(result.Rows[1].ElementType); Assert.Equal(3, result.Rows[1].LineNumber); } [Fact] public void Parse_TwoColumnFileWithoutElementType_RowsHaveNullElementType() { const string csv = "AttributeName,Value\nSetpoint,42\nName,Pump A\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); Assert.Equal(2, result.Rows.Count); Assert.All(result.Rows, r => Assert.Null(r.ElementType)); Assert.Equal("42", result.Rows[0].Value); Assert.Equal("Pump A", result.Rows[1].Value); } [Fact] public void Parse_QuotedValueWithComma_PreservesEmbeddedComma() { const string csv = "AttributeName,Value,ElementType\nName,\"a,b,c\",\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); var row = Assert.Single(result.Rows); Assert.Equal("Name", row.AttributeName); Assert.Equal("a,b,c", row.Value); Assert.Null(row.ElementType); } [Fact] public void Parse_DoubledQuoteEscape_UnescapesToSingleQuote() { const string csv = "AttributeName,Value,ElementType\nName,\"he said \"\"hi\"\"\",\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); var row = Assert.Single(result.Rows); Assert.Equal("he said \"hi\"", row.Value); } [Fact] public void Parse_EmptyValueField_YieldsNullValue() { const string csv = "AttributeName,Value,ElementType\nSetpoint,,\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); var row = Assert.Single(result.Rows); Assert.Equal("Setpoint", row.AttributeName); Assert.Null(row.Value); Assert.Null(row.ElementType); } [Fact] public void Parse_RowWithTooFewColumns_ProducesLineNumberedErrorAndExcludesRow() { const string csv = "AttributeName,Value,ElementType\nSetpoint\nName,Pump A,\n"; var result = OverrideCsvParser.Parse(csv); // Bad row on line 2 excluded; good row on line 3 retained. var row = Assert.Single(result.Rows); Assert.Equal("Name", row.AttributeName); Assert.Equal(3, row.LineNumber); var error = Assert.Single(result.Errors); Assert.Contains("2", error); } [Fact] public void Parse_BlankAttributeName_ProducesLineNumberedError() { const string csv = "AttributeName,Value,ElementType\n,42,Int32\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Rows); var error = Assert.Single(result.Errors); Assert.Contains("2", error); } [Fact] public void Parse_BlankLines_AreSkippedWithoutError() { const string csv = "AttributeName,Value,ElementType\n\nSetpoint,42,Int32\n \nName,Pump A,\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); Assert.Equal(2, result.Rows.Count); // LineNumber reflects the true source line (blank line 2 skipped). Assert.Equal(3, result.Rows[0].LineNumber); Assert.Equal(5, result.Rows[1].LineNumber); } [Fact] public void Parse_MissingHeader_ReturnsZeroRowsAndHeaderError() { const string csv = "Setpoint,42,Int32\nName,Pump A,\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Rows); var error = Assert.Single(result.Errors); Assert.Contains("header", error, StringComparison.OrdinalIgnoreCase); } [Fact] public void Parse_HeaderIsCaseInsensitiveAndTrimsWhitespace() { const string csv = "attributename, value , elementtype\nSetpoint,42,Int32\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); var row = Assert.Single(result.Rows); Assert.Equal("Setpoint", row.AttributeName); Assert.Equal("42", row.Value); Assert.Equal("Int32", row.ElementType); } [Fact] public void Parse_EmptyInput_ReturnsHeaderError() { var result = OverrideCsvParser.Parse(string.Empty); Assert.Empty(result.Rows); Assert.Single(result.Errors); } [Fact] public void Parse_UnquotedWhitespace_IsTrimmedButQuotedWhitespacePreserved() { const string csv = "AttributeName,Value,ElementType\n Setpoint , 42 ,Int32\nName,\" spaced \",\n"; var result = OverrideCsvParser.Parse(csv); Assert.Empty(result.Errors); Assert.Equal(2, result.Rows.Count); Assert.Equal("Setpoint", result.Rows[0].AttributeName); Assert.Equal("42", result.Rows[0].Value); Assert.Equal(" spaced ", result.Rows[1].Value); } }