Skip to content

Commit bdac830

Browse files
committed
Add discriminator-based polymorphism
1 parent e784ce7 commit bdac830

File tree

6 files changed

+728
-8
lines changed

6 files changed

+728
-8
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System.Text.Json.Serialization;
2+
using NUnit.Framework;
3+
using Tomlyn.Serialization;
4+
5+
namespace Tomlyn.Tests;
6+
7+
public class NewApiPolymorphismTests
8+
{
9+
[TomlPolymorphic(TypeDiscriminatorPropertyName = "kind")]
10+
[TomlDerivedType(typeof(Cat), "cat")]
11+
[TomlDerivedType(typeof(Dog), "dog")]
12+
private abstract class Animal
13+
{
14+
public string? Name { get; set; }
15+
}
16+
17+
private sealed class Cat : Animal
18+
{
19+
public int Lives { get; set; }
20+
}
21+
22+
private sealed class Dog : Animal
23+
{
24+
public bool GoodBoy { get; set; }
25+
}
26+
27+
[Test]
28+
public void Serialize_Polymorphic_WritesDiscriminator()
29+
{
30+
Animal value = new Cat { Name = "Nyan", Lives = 9 };
31+
var toml = TomlSerializer.Serialize(value);
32+
33+
Assert.That(toml, Does.Contain("kind"));
34+
Assert.That(toml, Does.Contain("cat"));
35+
Assert.That(toml, Does.Contain("Name"));
36+
Assert.That(toml, Does.Contain("Nyan"));
37+
Assert.That(toml, Does.Contain("Lives"));
38+
Assert.That(toml, Does.Contain("9"));
39+
}
40+
41+
[Test]
42+
public void Deserialize_Polymorphic_UsesDiscriminatorWhenNotFirst()
43+
{
44+
var toml =
45+
"""
46+
kind = "cat"
47+
Name = "Nyan"
48+
Lives = 9
49+
""";
50+
51+
var result = TomlSerializer.Deserialize<Animal>(toml);
52+
53+
Assert.That(result, Is.TypeOf<Cat>());
54+
var cat = (Cat)result!;
55+
Assert.That(cat.Name, Is.EqualTo("Nyan"));
56+
Assert.That(cat.Lives, Is.EqualTo(9));
57+
}
58+
59+
[Test]
60+
public void Deserialize_Polymorphic_UnknownDiscriminator_FailsByDefault()
61+
{
62+
var toml =
63+
"""
64+
kind = "fox"
65+
Name = "X"
66+
""";
67+
68+
Assert.Throws<TomlException>(() => TomlSerializer.Deserialize<Animal>(toml));
69+
}
70+
71+
[TomlPolymorphic(TypeDiscriminatorPropertyName = "kind")]
72+
[TomlDerivedType(typeof(DerivedPet), "derived")]
73+
private class Pet
74+
{
75+
public string? Name { get; set; }
76+
}
77+
78+
private sealed class DerivedPet : Pet
79+
{
80+
public int Age { get; set; }
81+
}
82+
83+
[Test]
84+
public void Deserialize_Polymorphic_UnknownDiscriminator_CanFallbackToBase()
85+
{
86+
var toml =
87+
"""
88+
kind = "unknown"
89+
Name = "Base"
90+
extra = 123
91+
""";
92+
93+
var options = new TomlSerializerOptions
94+
{
95+
PolymorphismOptions = new TomlPolymorphismOptions
96+
{
97+
TypeDiscriminatorPropertyName = "kind",
98+
UnknownDerivedTypeHandling = TomlUnknownDerivedTypeHandling.FallBackToBaseType,
99+
},
100+
};
101+
102+
var result = TomlSerializer.Deserialize<Pet>(toml, options);
103+
Assert.That(result, Is.TypeOf<Pet>());
104+
Assert.That(result!.Name, Is.EqualTo("Base"));
105+
}
106+
107+
[JsonPolymorphic(TypeDiscriminatorPropertyName = "kind")]
108+
[JsonDerivedType(typeof(JsonCat), "cat")]
109+
private abstract class JsonAnimal
110+
{
111+
public string? Name { get; set; }
112+
}
113+
114+
private sealed class JsonCat : JsonAnimal
115+
{
116+
public int Lives { get; set; }
117+
}
118+
119+
[Test]
120+
public void Deserialize_Polymorphic_RespectsSystemTextJsonAttributes()
121+
{
122+
var toml =
123+
"""
124+
kind = "cat"
125+
Name = "Ada"
126+
Lives = 9
127+
""";
128+
129+
var result = TomlSerializer.Deserialize<JsonAnimal>(toml);
130+
Assert.That(result, Is.TypeOf<JsonCat>());
131+
Assert.That(((JsonCat)result!).Lives, Is.EqualTo(9));
132+
}
133+
}

0 commit comments

Comments
 (0)