diff --git a/Excely.UnitTests/ClassListTableConverterTests.cs b/Excely.UnitTests/ClassListTableConverterTests.cs index 229dba7..c81c47f 100644 --- a/Excely.UnitTests/ClassListTableConverterTests.cs +++ b/Excely.UnitTests/ClassListTableConverterTests.cs @@ -104,9 +104,9 @@ public void ConvertFromDataWithCustomSchema_ShouldReturnCorrectList() // Arrange var table = new ExcelyTable(new List> { - new List { "數字", "文字", "日期", "Enum" }, - new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, - new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + new List { "數字", "文字", "日期", "Enum", null }, + new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1, "Ignored" }, + new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2, "Ignored" }, }); var options = new ClassListTableConverterOptions { diff --git a/Excely.UnitTests/DictionaryListTableConverterTests.cs b/Excely.UnitTests/DictionaryListTableConverterTests.cs new file mode 100644 index 0000000..3c8abf6 --- /dev/null +++ b/Excely.UnitTests/DictionaryListTableConverterTests.cs @@ -0,0 +1,237 @@ +using Excely.TableConverters; +using Excely.UnitTests.Models; + +namespace Excely.UnitTests +{ + [TestClass] + public class DictionaryListTableConverterTests + { + /// + /// 基礎轉換測試,最簡單的資料,使用預設邏輯。 + /// + [TestMethod] + public void ConvertFromData_ShouldReturnCorrectList() + { + // Arrange + var table = new ExcelyTable(new List> + { + new List { "IntValue", "StrigValue", "DateTimeValue", "EnumValue" }, + new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, + new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + }); + var converter = new DictionaryListTableConverter(); + + // Act + var result = converter.ConvertFrom(table).ToList(); + + // Assert + Assert.AreEqual(2, result.Count); + for (int i = 0; i < result.Count; i++) + { + Assert.AreEqual(table.Data[i + 1][0], result[i]["IntValue"]); + Assert.AreEqual(table.Data[i + 1][1], result[i]["StrigValue"]); + Assert.AreEqual(table.Data[i + 1][2], result[i]["DateTimeValue"]); + Assert.AreEqual(table.Data[i + 1][3], result[i]["EnumValue"]); + } + } + + /// + /// 基礎轉換測試,有可能為 Null 的資料,使用預設邏輯。 + /// + [TestMethod] + public void ConvertFromNullableData_ShouldReturnCorrectListOfSimpleNullableClass() + { + // Arrange + var table = new ExcelyTable(new List> + { + new List { "IntValue", "StrigValue", "DateTimeValue", "EnumValue" }, + new List { null, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, + new List { 1, null, DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + new List { 2, "Text2", null, SampleEnum.Enum3 }, + new List { 3, "Text3", DateTime.Parse("2023/1/3"), null }, + }); + var converter = new DictionaryListTableConverter(); + + // Act + var result = converter.ConvertFrom(table).ToList(); + + // Assert + Assert.AreEqual(4, result.Count); + for (int i = 0; i < result.Count; i++) + { + Assert.AreEqual(table.Data[i + 1][0], result[i]["IntValue"]); + Assert.AreEqual(table.Data[i + 1][1], result[i]["StrigValue"]); + Assert.AreEqual(table.Data[i + 1][2], result[i]["DateTimeValue"]); + Assert.AreEqual(table.Data[i + 1][3], result[i]["EnumValue"]); + } + } + + /// + /// 有 null 表頭不匯入。 + /// + [TestMethod] + public void ConvertFromDataWithNullSchema_ShouldReturnCorrectList() + { + // Arrange + var table = new ExcelyTable(new List> + { + new List { "IntValue", "StrigValue", "DateTimeValue", null }, + new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, + new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + }); + var converter = new DictionaryListTableConverter(); + + // Act + var result = converter.ConvertFrom(table).ToList(); + + // Assert + Assert.AreEqual(2, result.Count); + for (int i = 0; i < result.Count; i++) + { + Assert.AreEqual(table.Data[i + 1][0], result[i]["IntValue"]); + Assert.AreEqual(table.Data[i + 1][1], result[i]["StrigValue"]); + Assert.AreEqual(table.Data[i + 1][2], result[i]["DateTimeValue"]); + Assert.AreEqual(table.Data[i + 1][3], result[i]["3"]); + } + } + + /// + /// 自訂表頭測試。 + /// + [TestMethod] + public void ConvertFromDataWithCustomSchema_ShouldReturnCorrectList() + { + // Arrange + var table = new ExcelyTable(new List> + { + new List { "IntValue", "StrigValue", "DateTimeValue", "Enum" }, + new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, + new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + }); + var options = new DictionaryListTableConverterOptions + { + HasSchema = true, + CustomKeyNamePolicy = (index, field) => field + index, + }; + var converter = new DictionaryListTableConverter(options); + + // Act + var result = converter.ConvertFrom(table).ToList(); + + // Assert + Assert.AreEqual(2, result.Count); + for (int i = 0; i < result.Count; i++) + { + Assert.AreEqual(table.Data[i + 1][0], result[i]["IntValue0"]); + Assert.AreEqual(table.Data[i + 1][1], result[i]["StrigValue1"]); + Assert.AreEqual(table.Data[i + 1][2], result[i]["DateTimeValue2"]); + Assert.AreEqual(table.Data[i + 1][3], result[i]["Enum3"]); + } + } + + /// + /// 自訂表頭測試,忽略某些欄位。 + /// + [TestMethod] + public void ConvertFromDataWithCustomSchema_IgnoreSomeField_ShouldReturnCorrectList() + { + // Arrange + var table = new ExcelyTable(new List> + { + new List { "IntValue", "StrigValue", "DateTimeValue", "Enum" }, + new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, + new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + }); + var options = new DictionaryListTableConverterOptions + { + HasSchema = true, + CustomKeyNamePolicy = (index, field) => field == "Enum" ? null : field, + }; + var converter = new DictionaryListTableConverter(options); + + // Act + var result = converter.ConvertFrom(table).ToList(); + + // Assert + Assert.AreEqual(2, result.Count); + for (int i = 0; i < result.Count; i++) + { + Assert.AreEqual(table.Data[i + 1][0], result[i]["IntValue"]); + Assert.AreEqual(table.Data[i + 1][1], result[i]["StrigValue"]); + Assert.AreEqual(table.Data[i + 1][2], result[i]["DateTimeValue"]); + Assert.IsFalse(result[i].ContainsKey("Enum")); + } + } + + /// + /// 不含表頭測試,使用預設邏輯。 + /// + [TestMethod] + public void ConvertFromDataWithoutSchema_ShouldReturnCorrectList() + { + // Arrange + var table = new ExcelyTable(new List> + { + new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, + new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + }); + var options = new DictionaryListTableConverterOptions + { + HasSchema = false + }; + var converter = new DictionaryListTableConverter(options); + + // Act + var result = converter.ConvertFrom(table).ToList(); + + // Assert + Assert.AreEqual(2, result.Count); + for (int i = 0; i < result.Count; i++) + { + Assert.AreEqual(table.Data[i][0], result[i]["0"]); + Assert.AreEqual(table.Data[i][1], result[i]["1"]); + Assert.AreEqual(table.Data[i][2], result[i]["2"]); + Assert.AreEqual(table.Data[i][3], result[i]["3"]); + } + } + + /// + /// 自訂寫入值測試。 + /// + [TestMethod] + public void ConvertFromDataWithPropertyValueSettingPolicy_ShouldReturnCorrectList() + { +#pragma warning disable CS8605 // Unboxing 可能 null 值。 + // Arrange + var table = new ExcelyTable(new List> + { + new List { "IntValue", "StrigValue", "DateTimeValue", "EnumValue" }, + new List { 1, "Text1", DateTime.Parse("2023/1/1"), SampleEnum.Enum1 }, + new List { 2, "Text2", DateTime.Parse("2023/1/2"), SampleEnum.Enum2 }, + }); + var options = new DictionaryListTableConverterOptions + { + CustomValuePolicy = (key, value) => key switch + { + "IntValue" => (int)value * 2, + _ => value, + } + }; + var converter = new DictionaryListTableConverter(options); + + // Act + var result = converter.ConvertFrom(table).ToList(); + + // Assert + Assert.AreEqual(2, result.Count); + for (int i = 0; i < result.Count; i++) + { + Assert.AreEqual((int)table.Data[i + 1][0] * 2, result[i]["IntValue"]); + Assert.AreEqual(table.Data[i + 1][1], result[i]["StrigValue"]); + Assert.AreEqual(table.Data[i + 1][2], result[i]["DateTimeValue"]); + Assert.AreEqual(table.Data[i + 1][3], result[i]["EnumValue"]); + } +#pragma warning restore CS8605 // Unboxing 可能 null 值。 + } + } +} diff --git a/Excely.UnitTests/DictionaryListTableFactoryTests.cs b/Excely.UnitTests/DictionaryListTableFactoryTests.cs new file mode 100644 index 0000000..0af9420 --- /dev/null +++ b/Excely.UnitTests/DictionaryListTableFactoryTests.cs @@ -0,0 +1,126 @@ +using Excely.TableFactories; + +namespace Excely.UnitTests +{ + [TestClass] + public class DictionaryListTableFactoryTests + { + [TestMethod] + public void GetTable_WithDefaultOptions_ShouldIncludeAllPropertiesWithSchema() + { + // Arrange + var factory = new DictionaryListTableFactory(); + var testData = new List> + { + new Dictionary + { + { "Id", 1 }, + { "Name", "Alice" } + } + }; + + // Act + var table = factory.GetTable(testData); + + // Assert + Assert.AreEqual(2, table.MaxRowCount); // Including schema + Assert.AreEqual(2, table.MaxColumnCount); // Id and Name + Assert.AreEqual("Id", table.Data[0][0]); + Assert.AreEqual("Name", table.Data[0][1]); + Assert.AreEqual(1, table.Data[1][0]); + Assert.AreEqual("Alice", table.Data[1][1]); + } + + [TestMethod] + public void GetTable_WithOptionsNoSchema_ShouldExcludeSchema() + { + // Arrange + var options = new DictionaryListTableFactoryOptions { WithSchema = false }; + var factory = new DictionaryListTableFactory(options); + var testData = new List> + { + new Dictionary + { + { "Id", 1 }, + { "Name", "Alice" } + } + }; + + // Act + var table = factory.GetTable(testData); + + // Assert + Assert.AreEqual(1, table.MaxRowCount); // Excluding schema + Assert.AreEqual(1, table.Data[0][0]); + Assert.AreEqual("Alice", table.Data[0][1]); + } + + [TestMethod] + public void GetTable_WithCustomPropertyShowPolicy_ShouldFilterProperties() + { + // Arrange + var options = new DictionaryListTableFactoryOptions + { + KeyShowPolicy = key => key == "Name" + }; + var factory = new DictionaryListTableFactory(options); + var testData = new List> + { + new Dictionary + { + { "Id", 1 }, + { "Name", "Alice" } + } + }; + + // Act + var table = factory.GetTable(testData); + + // Assert + Assert.AreEqual(2, table.MaxRowCount); // Including schema + Assert.AreEqual(1, table.MaxColumnCount); // Only Name + Assert.AreEqual("Alice", table.Data[1][0]); + } + + [TestMethod] + public void GetTable_WithNullList_ShouldThrowArgumentNullException() + { + // Arrange + var factory = new DictionaryListTableFactory(); + + // Act & Assert + Assert.ThrowsException(() => factory.GetTable(null)); + } + + [TestMethod] + public void GetTable_WithCustomOrderPolicy_ShouldOrderColumnsAccordingly() + { + // Arrange + var options = new DictionaryListTableFactoryOptions + { + CustomValuePolicy = (key, obj) => + key == "Name" ? 1 : 2 + }; + var factory = new DictionaryListTableFactory(options); + var testData = new List> + { + new Dictionary + { + { "Id", 1 }, + { "Name", "Alice" } + } + }; + + // Act + var table = factory.GetTable(testData); + + // Assert + Assert.AreEqual("Id", table.Data[0][0]); + Assert.AreEqual("Name", table.Data[0][1]); + Assert.AreEqual(2, table.Data[1][0]); + Assert.AreEqual(1, table.Data[1][1]); + } + + // iHھڻݭnK[hծר... + } +} \ No newline at end of file diff --git a/Excely/TableConverters/DictionaryListTableConverter.cs b/Excely/TableConverters/DictionaryListTableConverter.cs index 7eaece0..f32df47 100644 --- a/Excely/TableConverters/DictionaryListTableConverter.cs +++ b/Excely/TableConverters/DictionaryListTableConverter.cs @@ -96,6 +96,6 @@ public class DictionaryListTableConverterOptions /// 輸入參數為 (Key, 原始值),輸出結果為「應寫入的值」。 /// 預設為原值。 /// - public Func CustomValuePolicy { get; set; } = (key, obj) => obj; + public Func CustomValuePolicy { get; set; } = (key, value) => value; } }