using ZB.MOM.WW.ScadaBridge.Commons.Types;
namespace ZB.MOM.WW.ScadaBridge.Commons.Tests;
public class NativeAlarmSourceOverrideCsvParserTests
{
/// Verifies that a simple file parses into rows with no errors.
[Fact]
public void Parse_SimpleFile_ReturnsRowsNoErrors()
{
const string csv =
"SourceName,Connection,SourceReference,Filter\n" +
"Pressure,ConnA,ns=2;s=Pump.Alarm,Active\n" +
"Module.Temp,ConnB,ns=2;s=Temp,\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Errors);
Assert.Equal(2, result.Rows.Count);
Assert.Equal("Pressure", result.Rows[0].SourceName);
Assert.Equal("ConnA", result.Rows[0].Connection);
Assert.Equal("ns=2;s=Pump.Alarm", result.Rows[0].SourceReference);
Assert.Equal("Active", result.Rows[0].Filter);
Assert.Equal(2, result.Rows[0].LineNumber);
Assert.Equal("Module.Temp", result.Rows[1].SourceName);
Assert.Equal("ConnB", result.Rows[1].Connection);
Assert.Equal("ns=2;s=Temp", result.Rows[1].SourceReference);
Assert.Null(result.Rows[1].Filter);
Assert.Equal(3, result.Rows[1].LineNumber);
}
/// Verifies that blank override fields become null so the inherited value applies.
[Fact]
public void Parse_BlankOverrideFields_BecomeNullInherited()
{
const string csv =
"SourceName,Connection,SourceReference,Filter\n" +
"Pressure,,,\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Errors);
var row = Assert.Single(result.Rows);
Assert.Equal("Pressure", row.SourceName);
Assert.Null(row.Connection);
Assert.Null(row.SourceReference);
Assert.Null(row.Filter);
}
/// Verifies that header names are matched case-insensitively.
[Fact]
public void Parse_HeaderCaseInsensitive_Accepted()
{
const string csv =
"sourcename,CONNECTION,SourceReference,filter\n" +
"Pressure,ConnA,ref,\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Errors);
Assert.Single(result.Rows);
}
/// Verifies that a quoted field preserves an embedded comma.
[Fact]
public void Parse_QuotedFieldWithComma_PreservesEmbeddedComma()
{
const string csv =
"SourceName,Connection,SourceReference,Filter\n" +
"Pressure,ConnA,\"ns=2;s=a,b,c\",Active\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Errors);
var row = Assert.Single(result.Rows);
Assert.Equal("ns=2;s=a,b,c", row.SourceReference);
}
/// Verifies that a missing header returns a header error.
[Fact]
public void Parse_MissingHeader_ReturnsHeaderError()
{
const string csv = "Pressure,ConnA,ref,Active\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Rows);
var error = Assert.Single(result.Errors);
Assert.Contains("SourceName,Connection,SourceReference,Filter", error);
}
/// Verifies that a row with the wrong column count reports a per-line error and is skipped.
[Fact]
public void Parse_WrongColumnCount_ReportsPerLineErrorAndSkipsRow()
{
const string csv =
"SourceName,Connection,SourceReference,Filter\n" +
"Pressure,ConnA\n" +
"Temp,ConnB,ref,Active\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
var error = Assert.Single(result.Errors);
Assert.Contains("Line 2", error);
Assert.Contains("expected 4 columns", error);
// Valid rows still flow through.
var row = Assert.Single(result.Rows);
Assert.Equal("Temp", row.SourceName);
}
/// Verifies that a blank source name reports an error.
[Fact]
public void Parse_BlankSourceName_ReportsError()
{
const string csv =
"SourceName,Connection,SourceReference,Filter\n" +
",ConnA,ref,Active\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Rows);
var error = Assert.Single(result.Errors);
Assert.Contains("SourceName must not be blank", error);
}
/// Verifies that an unterminated quote reports an error.
[Fact]
public void Parse_UnterminatedQuote_ReportsError()
{
const string csv =
"SourceName,Connection,SourceReference,Filter\n" +
"Pressure,ConnA,\"ns=2;s=open,Active\n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Rows);
Assert.Contains(result.Errors, e => e.Contains("Unterminated quoted field"));
}
/// Verifies that blank lines are skipped without an error.
[Fact]
public void Parse_BlankLinesSkippedWithoutError()
{
const string csv =
"SourceName,Connection,SourceReference,Filter\n" +
"\n" +
"Pressure,ConnA,ref,Active\n" +
" \n";
var result = NativeAlarmSourceOverrideCsvParser.Parse(csv);
Assert.Empty(result.Errors);
Assert.Single(result.Rows);
}
}