Skip to content

Commit 4eb5035

Browse files
committed
Expose DasherContext.IsValidTopLevelType and tweak logic/errors a bit.
1 parent a4305f8 commit 4eb5035

File tree

7 files changed

+104
-6
lines changed

7 files changed

+104
-6
lines changed

Dasher.Tests/Dasher.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
</Reference>
5959
</ItemGroup>
6060
<ItemGroup>
61+
<Compile Include="DasherContextTests.cs" />
6162
<Compile Include="DeserialiserPerfTests.cs" />
6263
<Compile Include="PackerPerfTests.cs" />
6364
<Compile Include="PackerTests.cs" />

Dasher.Tests/DasherContextTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using Xunit;
3+
4+
// ReSharper disable EmptyConstructor
5+
// ReSharper disable UnusedParameter.Local
6+
// ReSharper disable UnassignedGetOnlyAutoProperty
7+
// ReSharper disable MemberCanBePrivate.Local
8+
// ReSharper disable UnusedAutoPropertyAccessor.Local
9+
// ReSharper disable UnusedMember.Local
10+
11+
namespace Dasher.Tests
12+
{
13+
public sealed class DasherContextTests
14+
{
15+
private class Invalid1 { }
16+
private class Invalid2 { public Invalid2() {} }
17+
private class Invalid3 { private Invalid3(int i) {} public int I { get; } }
18+
19+
private class Valid1 { public Valid1(int i) {} public int I { get; } }
20+
private struct Valid2 { public Valid2(int i, float f) { I = i; } public int I { get; } }
21+
22+
[Fact]
23+
public void IsValidTopLevelType()
24+
{
25+
var context = new DasherContext();
26+
27+
Assert.False(context.IsValidTopLevelType(typeof(string)));
28+
Assert.False(context.IsValidTopLevelType(typeof(int)));
29+
Assert.False(context.IsValidTopLevelType(typeof(int?)));
30+
Assert.False(context.IsValidTopLevelType(typeof(Tuple<int, float>)));
31+
Assert.False(context.IsValidTopLevelType(typeof(TimeSpan)));
32+
Assert.False(context.IsValidTopLevelType(typeof(DateTime)));
33+
Assert.False(context.IsValidTopLevelType(typeof(Guid)));
34+
Assert.False(context.IsValidTopLevelType(typeof(Version)));
35+
Assert.False(context.IsValidTopLevelType(typeof(Invalid1)));
36+
Assert.False(context.IsValidTopLevelType(typeof(decimal)));
37+
Assert.False(context.IsValidTopLevelType(typeof(Union<int, string>)));
38+
39+
Assert.True(context.IsValidTopLevelType(typeof(Valid1)));
40+
Assert.True(context.IsValidTopLevelType(typeof(Valid2)));
41+
Assert.True(context.IsValidTopLevelType(typeof(Union<Valid1, Valid2>)));
42+
}
43+
}
44+
}

Dasher.Tests/DeserialiserTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void MultiplePropertiesExactMatch()
5151
public void DisallowsPrimitiveTypes()
5252
{
5353
var exception = Assert.Throws<DeserialisationException>(() => new Deserialiser<int>());
54-
Assert.Equal("Cannot deserialise type \"System.Int32\": Top-level primitive types are not supported. An object with properties supports future versioning.", exception.Message);
54+
Assert.Equal("Cannot deserialise type \"System.Int32\": Top level types must be complex to support future versioning.", exception.Message);
5555
}
5656

5757
[Fact]

Dasher.Tests/SerialiserTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public sealed class SerialiserTests
3434
public void DisallowsPrimitiveTypes()
3535
{
3636
var exception = Assert.Throws<SerialisationException>(() => new Serialiser<int>());
37-
Assert.Equal("Cannot serialise type \"System.Int32\": Top-level primitive types are not supported. An object with properties supports future versioning.", exception.Message);
37+
Assert.Equal("Cannot serialise type \"System.Int32\": Top level types must be complex to support future versioning.", exception.Message);
3838
}
3939

4040
[Fact]

Dasher/DasherContext.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,26 @@ internal bool TryGetTypeProvider(Type type, ICollection<string> errors, out ITyp
9999

100100
internal void ValidateTopLevelType(Type type, ICollection<string> errors)
101101
{
102-
if (type.IsPrimitive)
103-
errors.Add("Top-level primitive types are not supported. An object with properties supports future versioning.");
104-
105-
if (!_typeProviders.Any(p => p.CanProvide(type)))
102+
if (Union.IsUnionType(type))
103+
{
104+
foreach (var memberType in Union.GetTypes(type))
105+
ValidateTopLevelType(memberType, errors);
106+
}
107+
else if (_typeProviders.Any(p => p.CanProvide(type)))
108+
{
109+
errors.Add("Top level types must be complex to support future versioning.");
110+
}
111+
else
112+
{
106113
ComplexTypeProvider.TryValidateComplexType(type, errors);
114+
}
115+
}
116+
117+
public bool IsValidTopLevelType(Type type)
118+
{
119+
var errors = new List<string>(capacity: 0);
120+
ValidateTopLevelType(type, errors);
121+
return errors.Count == 0;
107122
}
108123
}
109124
}

Dasher/UnionTypes.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#endregion
2424

2525
using System;
26+
using System.Collections.Generic;
27+
using System.Reflection;
2628

2729
// ReSharper disable AssignNullToNotNullAttribute
2830
// ReSharper disable FieldCanBeMadeReadOnly.Local
@@ -32,6 +34,23 @@ namespace Dasher
3234
{
3335
// NOTE this file is generated
3436

37+
internal static class Union
38+
{
39+
public static bool IsUnionType(Type type)
40+
{
41+
return type.FullName.StartsWith("Dasher.Union`", StringComparison.Ordinal)
42+
&& type.Assembly == Assembly.GetExecutingAssembly();
43+
}
44+
45+
public static IReadOnlyList<Type> GetTypes(Type type)
46+
{
47+
if (!IsUnionType(type))
48+
throw new ArgumentException("Must be a union type.", nameof(type));
49+
50+
return type.GetGenericArguments();
51+
}
52+
}
53+
3554
/// <summary>
3655
/// Models a value which may be of one of 2 types.
3756
/// </summary>

Dasher/UnionTypes.tt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#endregion
2929

3030
using System;
31+
using System.Collections.Generic;
32+
using System.Reflection;
3133

3234
// ReSharper disable AssignNullToNotNullAttribute
3335
// ReSharper disable FieldCanBeMadeReadOnly.Local
@@ -36,6 +38,23 @@ using System;
3638
namespace Dasher
3739
{
3840
// NOTE this file is generated
41+
42+
internal static class Union
43+
{
44+
public static bool IsUnionType(Type type)
45+
{
46+
return type.FullName.StartsWith("Dasher.Union`", StringComparison.Ordinal)
47+
&& type.Assembly == Assembly.GetExecutingAssembly();
48+
}
49+
50+
public static IReadOnlyList<Type> GetTypes(Type type)
51+
{
52+
if (!IsUnionType(type))
53+
throw new ArgumentException("Must be a union type.", nameof(type));
54+
55+
return type.GetGenericArguments();
56+
}
57+
}
3958
<#
4059
for (var level = 2; level <= 16; level++)
4160
{

0 commit comments

Comments
 (0)