Skip to content

Commit

Permalink
Arrays can be used with unions as well
Browse files Browse the repository at this point in the history
  • Loading branch information
PawelGerr committed Oct 25, 2024
1 parent e7947f5 commit 9bec95d
Show file tree
Hide file tree
Showing 11 changed files with 384 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ public sealed class MemberTypeState : IEquatable<MemberTypeState>, IMemberInform
public MemberTypeSetting Setting { get; }

public MemberTypeState(
INamedTypeSymbol type,
string typeName,
ITypedMemberState typeState,
MemberTypeSetting setting)
{
Name = setting.Name ?? (typeState.IsNullableStruct ? $"Nullable{type.TypeArguments[0].Name}" : type.Name);
Name = setting.Name ?? typeName;
TypeFullyQualified = typeState.TypeFullyQualified;
TypeMinimallyQualified = typeState.TypeMinimallyQualified;
IsReferenceType = typeState.IsReferenceType;
Expand All @@ -30,6 +30,16 @@ public MemberTypeState(
Setting = setting;
}

public static string GetMemberTypeName(INamedTypeSymbol type, ITypedMemberState typeState)
{
return typeState.IsNullableStruct ? $"Nullable{type.TypeArguments[0].Name}" : type.Name;
}

public static string GetMemberTypeName(IArrayTypeSymbol type)
{
return type.ElementType.Name + "Array";
}

public override bool Equals(object? obj)
{
return obj is MemberTypeState other && Equals(other);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,17 +159,26 @@ private bool IsUnionCandidate(TypeDeclarationSyntax typeDeclaration)
return null;
}

if (memberType is not INamedTypeSymbol namedMemberType)
{
Logger.LogDebug("Type of the member must be a named type", tds);
return null;
}

var memberTypeSettings = settings.MemberTypeSettings[i];
memberType = memberType.IsReferenceType && memberTypeSettings.IsNullableReferenceType ? memberType.WithNullableAnnotation(NullableAnnotation.Annotated) : memberType;
var typeState = factory.Create(memberType);

var memberTypeState = new MemberTypeState(namedMemberType, typeState, memberTypeSettings);
string memberTypeName;

switch (memberType)
{
case INamedTypeSymbol namedTypeSymbol:
memberTypeName = MemberTypeState.GetMemberTypeName(namedTypeSymbol, typeState);
break;
case IArrayTypeSymbol arrayTypeSymbol:
memberTypeName = MemberTypeState.GetMemberTypeName(arrayTypeSymbol);
break;
default:
Logger.LogError("Type of the member must be a named type or array type", tds);
return null;
}

var memberTypeState = new MemberTypeState(memberTypeName, typeState, memberTypeSettings);
memberTypeStates = memberTypeStates.Add(memberTypeState);
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Thinktecture.Runtime.Tests.TestUnions;

// ReSharper disable once InconsistentNaming
[Union<string[], int>]
public partial class TestUnion_class_with_array;
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public void Should_return_correct_value_or_throw_exception_having_2_types()
new TestUnion_struct_string_int("text").Invoking(u => u.AsInt32.Should()).Should().Throw<InvalidOperationException>().WithMessage("'TestUnion_struct_string_int' is not of type 'int'.");
new TestUnion_struct_string_int(1).Invoking(u => u.AsString.Should()).Should().Throw<InvalidOperationException>().WithMessage("'TestUnion_struct_string_int' is not of type 'string'.");
new TestUnion_struct_string_int(1).AsInt32.Should().Be(1);

new TestUnion_class_with_array(["text"]).AsStringArray.Should().BeEquivalentTo(["text"]);
new TestUnion_class_with_array(["text"]).Invoking(u => u.AsInt32.Should()).Should().Throw<InvalidOperationException>().WithMessage("'TestUnion_class_with_array' is not of type 'int'.");
new TestUnion_class_with_array(1).Invoking(u => u.AsStringArray.Should()).Should().Throw<InvalidOperationException>().WithMessage("'TestUnion_class_with_array' is not of type 'string[]'.");
new TestUnion_class_with_array(1).AsInt32.Should().Be(1);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public void Should_have_explicit_casts_to_value_having_2_types()

((int)new TestUnion_struct_string_int(1)).Should().Be(1);
FluentActions.Invoking(() => (string)new TestUnion_struct_string_int(1)).Should().Throw<InvalidOperationException>().WithMessage("'TestUnion_struct_string_int' is not of type 'string'.");

((string[])new TestUnion_class_with_array(["text"])).Should().BeEquivalentTo(["text"]);
FluentActions.Invoking(() => (int)new TestUnion_class_with_array(["text"])).Should().Throw<InvalidOperationException>().WithMessage("'TestUnion_class_with_array' is not of type 'int'.");
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public void Should_have_implicit_casts_from_value_having_2_values()

TestUnion_struct_string_int intStructUnion = 42;
intStructUnion.Value.Should().Be(42);

TestUnion_class_with_array arrayClassUnion = new[] { "text" };
arrayClassUnion.Value.Should().BeEquivalentTo(new[] { "text" });
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public void Should_use_correct_index_having_2_types()
new TestUnion_struct_string_int("text").IsInt32.Should().BeFalse();
new TestUnion_struct_string_int(1).IsString.Should().BeFalse();
new TestUnion_struct_string_int(1).IsInt32.Should().BeTrue();

new TestUnion_class_with_array(["text"]).IsStringArray.Should().BeTrue();
new TestUnion_class_with_array(["text"]).IsInt32.Should().BeFalse();
new TestUnion_class_with_array(1).IsStringArray.Should().BeFalse();
new TestUnion_class_with_array(1).IsInt32.Should().BeTrue();
}

[Fact]
Expand Down
18 changes: 18 additions & 0 deletions test/Thinktecture.Runtime.Extensions.Tests/UnionTests/Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ public void Should_use_correct_arg_having_2_values(int index, object expected)
calledActionOn.Should().Be(expected);
}

[Theory]
[InlineData(1, "text")]
[InlineData(2, 42)]
public void Should_use_correct_arg_having_2_values_with_array(int index, object expected)
{
var value = index switch
{
1 => new TestUnion_class_with_array(["text"]),
2 => new TestUnion_class_with_array(42),
_ => throw new Exception()
};

var calledActionOn = value.Map(stringArray: (object)"text",
int32: 42);

calledActionOn.Should().Be(expected);
}

[Theory]
[InlineData(1, "text")]
[InlineData(2, 42)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public void Should_return_string_representation_of_the_inner_value_having_2_type

new TestUnion_struct_string_int("text").ToString().Should().Be("text");
new TestUnion_struct_string_int(42).ToString().Should().Be("42");

new TestUnion_class_with_array(["text"]).ToString().Should().Be("System.String[]");
new TestUnion_class_with_array(42).ToString().Should().Be("42");
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public void Should_return_correct_value_having_2_types()

new TestUnion_struct_string_int("text").Value.Should().Be("text");
new TestUnion_struct_string_int(1).Value.Should().Be(1);

new TestUnion_class_with_array(["text"]).Value.Should().BeEquivalentTo(new[] { "text" });
new TestUnion_class_with_array(1).Value.Should().Be(1);
}

[Fact]
Expand Down

0 comments on commit 9bec95d

Please sign in to comment.