Skip to content

Commit

Permalink
Fix enums used as table keys throwing exception (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
ITR13 authored Feb 26, 2025
1 parent 0d521fb commit 0f83b66
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 31 deletions.
22 changes: 0 additions & 22 deletions Tomlet.Tests/EnumSerializationTests.cs

This file was deleted.

102 changes: 102 additions & 0 deletions Tomlet.Tests/EnumTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Tomlet.Tests.TestModelClasses;
using Xunit;
using Xunit.Abstractions;

namespace Tomlet.Tests;

public class EnumTests
{
private readonly ITestOutputHelper _testOutputHelper;

public EnumTests(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}

[Fact]
public void CanSerializeEnum()
{
var toml = TomletMain.TomlStringFrom(new {EnumValue = TestEnum.Value1}).Trim();
Assert.Equal("EnumValue = \"Value1\"", toml);
}

[Fact]
public void SerializingAnUndefinedEnumValueThrows()
{
var testObj = new {EnumValue = (TestEnum)4};
Assert.Throws<ArgumentException>(() => TomletMain.TomlStringFrom(testObj));
}

[Fact]
public void CanSerializeDictWithEnumValues()
{
var testObj = new Dictionary<TestEnum, int> {{TestEnum.Value1, 1}, {TestEnum.Value2, 2}, {TestEnum.Value3, 3}};
var toml = TomletMain.TomlStringFrom(testObj);
Assert.Equal("Value1 = 1\nValue2 = 2\nValue3 = 3\n", toml);
}

[Fact]
public void CanSerializeNonInlinedClass()
{
var testObj = new Dictionary<TestEnum, ClassWithDoNotInlineMembers>
{
{
TestEnum.Value1, new ClassWithDoNotInlineMembers
{
ShouldNotBeInlinedField = new Dictionary<string, string> {{"Key", "Value1"}}
}
},
};
var toml = TomletMain.TomlStringFrom(testObj);
var expected = "[Value1]\nShouldBeInlined = { }\n[Value1.ShouldNotBeInlinedField]\nKey = \"Value1\"\n\n[Value1.ShouldNotBeInlinedProp]\n\n\n";
Assert.Equal(expected, toml);
}

[Fact]
public void CanDeserializeEnumDictionary()
{
var toml = "Value1 = 1\nValue2 = 2\nValue3 = 3\n";
var result = TomletMain.To<Dictionary<TestEnum, int>>(toml);
var expected = new Dictionary<TestEnum, int> {{TestEnum.Value1, 1}, {TestEnum.Value2, 2}, {TestEnum.Value3, 3}};
Assert.Equal(expected, result);
}

[Fact]
public void CanDeserializeEnumDictionaryWithFields()
{
var toml = @"
[Value1]
a = 'A'
b = 'B'
";
var result = TomletMain.To<Dictionary<TestEnum, Subname>>(toml);
var expected = new Dictionary<TestEnum, Subname>
{
{TestEnum.Value1, new Subname {a = "A", b = "B"}},
};

Assert.Equal(expected, result);
}

[Fact]
public void CanDeserializeEnumDictionaryInClass()
{
var toml = @"
[Subnames]
[Subnames.Value1]
a = 'A'
b = 'B'
";
var result = TomletMain.To<TomlTestClassWithEnumDict>(toml);
var expected = new TomlTestClassWithEnumDict
{
Subnames = new Dictionary<TestEnum, Subname> {{TestEnum.Value1, new Subname {a = "A", b = "B"}}},
};

Assert.Equal(expected.Subnames, result.Subnames);
}
}
7 changes: 0 additions & 7 deletions Tomlet.Tests/TestModelClasses/Name.cs

This file was deleted.

27 changes: 27 additions & 0 deletions Tomlet.Tests/TestModelClasses/Subname.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;

namespace Tomlet.Tests.TestModelClasses;

public class Subname
{
public string a;
public string b;

protected bool Equals(Subname other)
{
return a == other.a && b == other.b;
}

public override bool Equals(object obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Subname)obj);
}

public override int GetHashCode()
{
return HashCode.Combine(a, b);
}
}
File renamed without changes.
9 changes: 9 additions & 0 deletions Tomlet.Tests/TestModelClasses/TomlTestClassWithEnumDict.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;
using Tomlet.Tests.TestModelClasses;

namespace Tomlet.Tests;

public class TomlTestClassWithEnumDict
{
public Dictionary<TestEnum, Subname> Subnames;
}
File renamed without changes.
22 changes: 20 additions & 2 deletions Tomlet/TomlSerializationMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,14 +382,32 @@ private static Deserialize<Dictionary<TKey, TValue>> PrimitiveKeyedDictionaryDes
#endif
{
var valueDeserializer = GetDeserializer(typeof(TValue), options);

var type = typeof(TKey);
return value =>
{
if (value is not TomlTable table)
throw new TomlTypeMismatchException(typeof(TomlTable), value.GetType(), typeof(Dictionary<TKey, TValue>));

return table.Entries.ToDictionary(
entry => (TKey)(entry.Key as IConvertible).ToType(typeof(TKey), CultureInfo.InvariantCulture),
entry =>
{
if (!type.IsEnum)
{
return (TKey)(entry.Key as IConvertible).ToType(typeof(TKey), CultureInfo.InvariantCulture);
}

try
{
return (TKey)Enum.Parse(type, entry.Key, true);
}
catch (ArgumentException)
{
if (options.IgnoreInvalidEnumValues)
return (TKey)Enum.GetValues(type).GetValue(0)!;

throw new TomlEnumParseException(entry.Key, typeof(TKey));
}
},
entry => (TValue)valueDeserializer(entry.Value)
);
};
Expand Down

0 comments on commit 0f83b66

Please sign in to comment.