using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Commons.Csv; namespace ZB.MOM.WW.OtOpcUa.Commons.Tests.Csv; /// /// Quote-on-demand and terminator behaviour for : a field is quoted only when /// it must be (delimiter / quote / CR / LF), internal quotes double, CRLF terminates records by /// default (configurable), and no terminator trails the final row. /// public sealed class CsvWriterTests { [Fact] public void Writes_simple_rows_with_crlf_default() { var csv = CsvWriter.WriteToString(new[] { new[] { "a", "b", "c" }, new[] { "d", "e", "f" }, }); csv.ShouldBe("a,b,c\r\nd,e,f"); } [Fact] public void No_trailing_newline_after_last_row() { CsvWriter.WriteToString(new[] { new[] { "a" } }).ShouldBe("a"); } [Fact] public void Empty_rows_yield_empty_string() { CsvWriter.WriteToString(Array.Empty()).ShouldBe(""); } // ---- quote-on-demand ---- [Fact] public void Plain_field_is_not_quoted() { CsvWriter.WriteToString(new[] { new[] { "plain" } }).ShouldBe("plain"); } [Fact] public void Field_with_comma_is_quoted() { CsvWriter.WriteToString(new[] { new[] { "a,b" } }).ShouldBe("\"a,b\""); } [Fact] public void Field_with_quote_is_quoted_and_doubled() { CsvWriter.WriteToString(new[] { new[] { "a\"b" } }).ShouldBe("\"a\"\"b\""); } [Fact] public void Field_with_lf_is_quoted() { CsvWriter.WriteToString(new[] { new[] { "a\nb" } }).ShouldBe("\"a\nb\""); } [Fact] public void Field_with_cr_is_quoted() { CsvWriter.WriteToString(new[] { new[] { "a\rb" } }).ShouldBe("\"a\rb\""); } [Fact] public void Leading_and_trailing_spaces_are_not_quoted() { // RFC does not require quoting for spaces; the parser preserves them either way. CsvWriter.WriteToString(new[] { new[] { " a " } }).ShouldBe(" a "); } [Fact] public void Empty_fields_are_written_bare() { CsvWriter.WriteToString(new[] { new[] { "a", "", "c" } }).ShouldBe("a,,c"); } [Fact] public void Null_field_is_written_as_empty() { CsvWriter.WriteToString(new[] { new[] { "a", null, "c" } }).ShouldBe("a,,c"); } // ---- options ---- [Fact] public void QuoteAllFields_forces_every_field_quoted() { CsvWriter.WriteToString(new[] { new[] { "a", "b" } }, quoteAllFields: true) .ShouldBe("\"a\",\"b\""); } [Fact] public void Custom_newline_lf() { CsvWriter.WriteToString(new[] { new[] { "a" }, new[] { "b" } }, newline: "\n") .ShouldBe("a\nb"); } [Fact] public void Custom_delimiter_semicolon_quotes_on_semicolon_not_comma() { CsvWriter.WriteToString(new[] { new[] { "a,b", "c;d" } }, delimiter: ';') .ShouldBe("a,b;\"c;d\""); } [Fact] public void Writes_to_a_textwriter() { var sw = new StringWriter(); CsvWriter.Write(sw, new[] { new[] { "x", "y" } }); sw.ToString().ShouldBe("x,y"); } [Fact] public void Delimiter_may_not_be_a_quote() { Should.Throw(() => CsvWriter.WriteToString(new[] { new[] { "a" } }, delimiter: '"')); } }