diff --git a/TIASshot.Tests/IoUtilWriteInfoTests.cs b/TIASshot.Tests/IoUtilWriteInfoTests.cs
new file mode 100644
index 0000000..dff11c1
--- /dev/null
+++ b/TIASshot.Tests/IoUtilWriteInfoTests.cs
@@ -0,0 +1,92 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using NUnit.Framework;
+
+namespace TIASshot.Tests {
+ ///
+ /// IoUtil.WriteInfo(撮影情報 Info.csv の書き出し)のテスト.
+ /// 値にカンマ・ダブルクォート・改行が含まれても 1 項目が 1 行(キー,値 の 2 列)に保たれ,
+ /// RFC 4180 に従ってクォートされることを検証する.それ以外の値は従来どおりそのまま出力する.
+ ///
+ [TestFixture]
+ public class IoUtilWriteInfoTests {
+
+ private string _csvPath;
+
+ [SetUp]
+ public void SetUp() {
+ _csvPath = Path.GetTempFileName();
+ }
+
+ [TearDown]
+ public void TearDown() {
+ if (File.Exists(_csvPath)) File.Delete(_csvPath);
+ }
+
+ ///
+ /// 本番(RunShotLoop)と同じく new StreamWriter(path) で WriteInfo を呼び,
+ /// 先頭の撮影日時行を除いた本文を返す
+ ///
+ private string WriteAndReadBody(Dictionary info) {
+ using (var sw = new StreamWriter(_csvPath)) {
+ IoUtil.WriteInfo(sw, info);
+ }
+ var text = File.ReadAllText(_csvPath, Encoding.UTF8);
+ var firstNewLine = text.IndexOf("\r\n");
+ return text.Substring(firstNewLine + 2);
+ }
+
+ [Test]
+ public void WriteInfo_特殊文字を含まない値_従来どおりそのまま出力する() {
+ var info = new Dictionary {
+ { "データ名", "subject01" },
+ { "Exposure(ms)", "12.5" },
+ { "校正データ", @"C:\Data\2026-10-06\10_00_00-校正" },
+ };
+
+ var body = WriteAndReadBody(info);
+
+ Assert.That(body, Is.EqualTo(
+ "データ名,subject01\r\n" +
+ "Exposure(ms),12.5\r\n" +
+ "校正データ,C:\\Data\\2026-10-06\\10_00_00-校正\r\n"));
+ }
+
+ [Test]
+ public void WriteInfo_値にカンマを含む_ダブルクォートで囲む() {
+ var info = new Dictionary { { "データ名", "山田,太郎" } };
+
+ var body = WriteAndReadBody(info);
+
+ Assert.That(body, Is.EqualTo("データ名,\"山田,太郎\"\r\n"));
+ }
+
+ [Test]
+ public void WriteInfo_値にダブルクォートを含む_二重化してダブルクォートで囲む() {
+ var info = new Dictionary { { "データ名", "a\"b" } };
+
+ var body = WriteAndReadBody(info);
+
+ Assert.That(body, Is.EqualTo("データ名,\"a\"\"b\"\r\n"));
+ }
+
+ [Test]
+ public void WriteInfo_値に改行を含む_ダブルクォートで囲み1レコードに保つ() {
+ var info = new Dictionary { { "データ名", "a\r\nb" } };
+
+ var body = WriteAndReadBody(info);
+
+ Assert.That(body, Is.EqualTo("データ名,\"a\r\nb\"\r\n"));
+ }
+
+ [Test]
+ public void WriteInfo_値がnull_空欄として出力する() {
+ var info = new Dictionary { { "データ名", null } };
+
+ var body = WriteAndReadBody(info);
+
+ Assert.That(body, Is.EqualTo("データ名,\r\n"));
+ }
+ }
+}
diff --git a/TIASshot.Tests/TIASshot.Tests.csproj b/TIASshot.Tests/TIASshot.Tests.csproj
index 2ab809f..504bc4a 100644
--- a/TIASshot.Tests/TIASshot.Tests.csproj
+++ b/TIASshot.Tests/TIASshot.Tests.csproj
@@ -93,6 +93,7 @@
+