746267c2a2
ImportEquipmentModal split each line on commas, so a quoted Manufacturer with a comma silently shifted every later column. EquipmentCsvParser reads through the shared Commons CsvParser (the raw-tag importer's authority): quoted fields, doubled quotes, CRLF and blank lines parse; malformed quoting is an error, not a guess. Header/shape messages are unchanged. Refs #745 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
63 lines
2.2 KiB
C#
63 lines
2.2 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
|
|
|
|
/// <summary>R04 S6: the equipment CSV import reads RFC 4180 through the shared CsvParser.</summary>
|
|
[Trait("Category", "Unit")]
|
|
public sealed class EquipmentCsvParserTests
|
|
{
|
|
private const string Header = "Name,MachineCode,UnsLineId,ZTag,SAPID,Manufacturer,Model";
|
|
|
|
[Fact]
|
|
public void A_quoted_comma_stays_in_its_column()
|
|
{
|
|
var (rows, error) = EquipmentCsvParser.Parse(
|
|
Header + "\nPress 1,MC-1,LINE-1,Z1,S1,\"Acme, Inc.\",X200\n");
|
|
|
|
error.ShouldBeNull();
|
|
rows!.Single().Manufacturer.ShouldBe("Acme, Inc.");
|
|
// The column after the quoted comma did not shift.
|
|
rows!.Single().Model.ShouldBe("X200");
|
|
}
|
|
|
|
[Fact]
|
|
public void Doubled_quotes_crlf_and_blank_lines_parse()
|
|
{
|
|
var (rows, error) = EquipmentCsvParser.Parse(
|
|
Header + "\r\n\r\n\"Press \"\"A\"\"\",MC-1,LINE-1,,,,\r\nPress B,MC-2,LINE-1\r\n");
|
|
|
|
error.ShouldBeNull();
|
|
rows!.Select(r => r.Name).ShouldBe(["Press \"A\"", "Press B"]);
|
|
rows![0].ZTag.ShouldBeNull();
|
|
rows[1].Manufacturer.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Header_and_shape_errors_are_reported()
|
|
{
|
|
EquipmentCsvParser.Parse("").Error.ShouldBe("CSV is empty.");
|
|
EquipmentCsvParser.Parse(Header).Error.ShouldBe("Need a header row and at least one data row.");
|
|
EquipmentCsvParser.Parse("Name,Code,UnsLineId\na,b,c").Error!.ShouldContain("Header column #2 must be 'MachineCode'");
|
|
EquipmentCsvParser.Parse(Header + "\nonly,two").Error!.ShouldContain("Row 1: too few columns");
|
|
}
|
|
|
|
[Fact]
|
|
public void Malformed_quoting_is_an_error_not_a_guess()
|
|
{
|
|
var (rows, error) = EquipmentCsvParser.Parse(Header + "\nPress,MC-1,LINE-1,\"unterminated\n");
|
|
|
|
rows.ShouldBeNull();
|
|
error!.ShouldStartWith("The CSV is malformed:");
|
|
}
|
|
|
|
[Fact]
|
|
public void Modal_delegates_to_the_parser()
|
|
{
|
|
var src = AdminUiSource.Read("Components", "Shared", "Uns", "ImportEquipmentModal.razor");
|
|
src.ShouldContain("EquipmentCsvParser.Parse(csv)");
|
|
src.ShouldNotContain(".Split(',')");
|
|
}
|
|
}
|