Skip to content

Commit

Permalink
Merge pull request #93 from max-ieremenko/release/1.4.8
Browse files Browse the repository at this point in the history
Release/1.4.8
  • Loading branch information
max-ieremenko authored May 29, 2022
2 parents f77e25e + c097c6e commit d0f5795
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected override void Generate()
Output
.AppendAttribute(typeof(SerializableAttribute))
.AppendAttribute(typeof(DataContractAttribute), "Name = \"m\"", "Namespace = \"s\"")
.Append("internal sealed class ")
.Append("public sealed class ")
.Append(nameof(Message))
.Append("<");

Expand All @@ -54,6 +54,9 @@ protected override void Generate()

using (Output.Indent())
{
BuildFields();
Output.AppendLine();

BuildCtorDefault();
Output.AppendLine();

Expand Down Expand Up @@ -97,14 +100,24 @@ private void BuildCtorFull()
for (var i = 0; i < _propertiesCount; i++)
{
Output
.AppendFormat("Value{0} = value{0}", i + 1)
.AppendFormat("_value{0} = value{0}", i + 1)
.AppendLine(";");
}
}

Output.AppendLine("}");
}

private void BuildFields()
{
for (var i = 0; i < _propertiesCount; i++)
{
Output
.AppendFormat("private T{0} _value{0};", i + 1)
.AppendLine();
}
}

private void BuildProperties()
{
for (var i = 0; i < _propertiesCount; i++)
Expand All @@ -113,9 +126,22 @@ private void BuildProperties()
Output
.AppendLine()
.AppendAttribute(typeof(DataMemberAttribute), string.Format("Name = \"v{0}\"", order), string.Format("Order = {0}", order))
.AppendLine()
.AppendFormat("public T{0} Value{0}", order)
.AppendLine(" { get; set; }");
.AppendLine()
.AppendLine("{");

using (Output.Indent())
{
Output
.Append("get { return _value")
.Append(order)
.AppendLine("; }")
.Append("set { _value")
.Append(order)
.AppendLine(" = value; }");
}

Output.AppendLine("}");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// <copyright>
// Copyright 2022 Max Ieremenko
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Runtime.Serialization;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using NUnit.Framework;
using ServiceModel.Grpc.Channel;
using ServiceModel.Grpc.TestApi;
using Shouldly;

namespace ServiceModel.Grpc.DesignTime.Generator.Internal.CSharp;

[TestFixture]
public class CSharpMessageBuilderTest : MessageBuilderTestBase
{
private AssemblyLoadContext _loadContext = null!;

[OneTimeSetUp]
public void BeforeAll()
{
_loadContext = new AssemblyLoadContext(nameof(CSharpMessageBuilderTest), isCollectible: true);
}

[OneTimeTearDown]
public void AfterAll()
{
_loadContext.Unload();
}

protected override Type GetMessageType(Type[] typeArguments)
{
if (typeArguments.Length == 0)
{
return typeof(Message);
}

var genericType = FindOrCompileMessage(typeArguments.Length);
return genericType.MakeGenericType(typeArguments);
}

private Type FindOrCompileMessage(int propertiesCount)
{
var ns = typeof(CSharpMessageBuilderTest).Namespace!;
var assemblyName = typeof(CSharpMessageBuilderTest) + propertiesCount.ToString(CultureInfo.InvariantCulture);

var assembly = _loadContext.Assemblies.FirstOrDefault(i => i.GetName().Name == assemblyName);
if (assembly == null)
{
assembly = CompileMessage(assemblyName, ns, propertiesCount);
}

var messageTypeName = ns + ".Message" + "`" + propertiesCount.ToString(CultureInfo.InvariantCulture);

return assembly.GetType(messageTypeName, true, false)!;
}

private Assembly CompileMessage(string assemblyName, string ns, int propertiesCount)
{
var output = new CodeStringBuilder();
output.Append("namespace ").Append(ns).AppendLine(";");

new CSharpMessageBuilder(propertiesCount).GenerateMemberDeclaration(output);

var syntaxTree = SyntaxFactory.ParseSyntaxTree(
output.AsStringBuilder().ToString(),
CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10));

var compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location)!, "System.Runtime.dll")),
MetadataReference.CreateFromFile(typeof(DataContractAttribute).Assembly.Location),
MetadataReference.CreateFromFile(typeof(ExcludeFromCodeCoverageAttribute).Assembly.Location)
},
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

var peStream = new MemoryStream();
var emitResult = compilation.Emit(peStream);
emitResult.Success.ShouldBeTrue();

peStream.Position = 0;
return _loadContext.LoadFromStream(peStream);
}
}
86 changes: 8 additions & 78 deletions Sources/ServiceModel.Grpc.Test/Internal/Emit/MessageBuilderTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// <copyright>
// Copyright 2020 Max Ieremenko
// Copyright 2020-2022 Max Ieremenko
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -15,86 +15,16 @@
// </copyright>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using NUnit.Framework;
using ServiceModel.Grpc.TestApi;
using Shouldly;

namespace ServiceModel.Grpc.Internal.Emit
namespace ServiceModel.Grpc.Internal.Emit;

[TestFixture]
public class MessageBuilderTest : MessageBuilderTestBase
{
[TestFixture]
public class MessageBuilderTest
protected override Type GetMessageType(Type[] typeArguments)
{
[Test]
[TestCaseSource(nameof(GetMessageTypeTestCases))]
public void GetMessageType(Type[] typeArguments)
{
var actual = MessageBuilder.GetMessageType(typeArguments);
MessageBuilder.GetMessageType(typeArguments).ShouldBe(actual);

actual.ShouldNotBeNull();
Activator.CreateInstance(actual).ShouldNotBeNull(); // default ctor

actual.GetCustomAttribute<SerializableAttribute>().ShouldNotBeNull();
actual.GetCustomAttribute<DataContractAttribute>().ShouldNotBeNull();

// new (,,,,)
actual.Constructor(typeArguments).IsPublic.ShouldBeTrue();

var values = new object[typeArguments.Length];
for (var i = 0; i < typeArguments.Length; i++)
{
values[i] = "the value " + i;
}

////Console.WriteLine(actual.Constructor(typeArguments).Disassemble());
var instance = actual.Constructor(typeArguments).Invoke(values);

for (var i = 0; i < typeArguments.Length; i++)
{
var property = actual.InstanceProperty("Value" + (i + 1));

property.ShouldNotBeNull();
property.PropertyType.ShouldBe(typeArguments[i]);

property.GetMethod.ShouldNotBeNull();
property.GetMethod!.IsPublic.ShouldBeTrue();
property.SetMethod.ShouldNotBeNull();
property.SetMethod!.IsPublic.ShouldBeTrue();

if (i == 255)
{
Console.WriteLine(property.GetMethod.Disassemble());
}

property.GetValue(instance).ShouldBe(values[i]);
property.SetValue(instance, "new " + values[i]);
property.GetValue(instance).ShouldBe("new " + values[i]);

var dataMember = property.GetCustomAttribute<DataMemberAttribute>();
dataMember.ShouldNotBeNull();
dataMember!.Name.ShouldBe("v" + (i + 1));
dataMember.Order.ShouldBe(i + 1);
}
}

private static IEnumerable<TestCaseData> GetMessageTypeTestCases()
{
var cases = Enumerable.Range(0, 10).ToList();
cases.Add(255);
cases.Add(1000);

foreach (var i in cases)
{
object test = Enumerable.Range(0, i).Select(_ => typeof(string)).ToArray();
yield return new TestCaseData(test)
{
TestName = i + " args"
};
}
}
return MessageBuilder.GetMessageType(typeArguments);
}
}
}
Loading

0 comments on commit d0f5795

Please sign in to comment.