Skip to content

Commit

Permalink
Refactor sample generator in mgmt (#5107)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArcturusZhang authored Nov 26, 2024
1 parent 1c6a0f2 commit 53fbd40
Show file tree
Hide file tree
Showing 62 changed files with 2,366 additions and 3,813 deletions.
4 changes: 0 additions & 4 deletions src/AutoRest.CSharp/Common/AutoRest/Plugins/CSharpGen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ public async Task<GeneratedCodeWorkspace> ExecuteAsync(CodeModel codeModel)
var inputNamespace = new CodeModelConverter(codeModel, schemaUsageProvider).CreateNamespace();
MgmtContext.Initialize(new BuildContext<MgmtOutputLibrary>(inputNamespace, sourceInputModel));
await MgmtTarget.ExecuteAsync(project);
if (Configuration.MgmtTestConfiguration is not null && !Configuration.MgmtConfiguration.MgmtDebug.ReportOnly)
await MgmtTestTarget.ExecuteAsync(project, inputNamespace, sourceInputModel);
GenerateMgmtReport(project);
}
else
Expand Down Expand Up @@ -88,8 +86,6 @@ public async Task<GeneratedCodeWorkspace> ExecuteAsync(InputNamespace rootNamesp
InputNamespaceTransformer.Transform(rootNamespace);
MgmtContext.Initialize(new BuildContext<MgmtOutputLibrary>(rootNamespace, sourceInputModel));
await MgmtTarget.ExecuteAsync(project);
if (Configuration.GenerateSampleProject)
await MgmtTestTarget.ExecuteAsync(project, rootNamespace, sourceInputModel);
}
else
{
Expand Down
40 changes: 38 additions & 2 deletions src/AutoRest.CSharp/Common/Input/CodeModelConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,49 @@ private InputOperation CreateOperation(ServiceRequest serviceRequest, Operation
return result;
}

private static InputExampleValue HandleRawExampleValue(InputType inputType, object? rawValue)
{
if (rawValue == null)
{
return InputExampleValue.Null(inputType);
}
var type = rawValue.GetType();
if (type.IsGenericType)
{
// handle dictionary
if (type == typeof(Dictionary<object, object>))
{
var values = new Dictionary<string, InputExampleValue>();
foreach (var (key, value) in (Dictionary<object, object>)rawValue)
{
// key is always a string
// since we do not have a schema for the value type here, we use unknown
values.Add((string)key, HandleRawExampleValue(InputPrimitiveType.Unknown, value));
}
return new InputExampleObjectValue(inputType, values);
}
// handle list
if (type == typeof(List<object>))
{
var values = new List<InputExampleValue>();
foreach (var item in (List<object>)rawValue)
{
values.Add(HandleRawExampleValue(InputPrimitiveType.Unknown, item));
}
return new InputExampleListValue(inputType, values);
}
}

// the deserialization part of the test modeler output has a bug that all the primitive types are deserialized as strings, here we should convert them according to its real type
return new InputExampleRawValue(inputType, ConvertRawValue(inputType, rawValue));
}

private InputExampleValue CreateExampleValue(ExampleValue exampleValue)
{
var inputType = CreateType(exampleValue.Schema, exampleValue.Schema.Extensions?.Format, false);
if (exampleValue.RawValue != null)
{
// test modeler has a bug that all the primitive types are deserialized as strings, here we should convert them according to its real type
return new InputExampleRawValue(inputType, ConvertRawValue(inputType, exampleValue.RawValue));
return HandleRawExampleValue(inputType, exampleValue.RawValue);
}
if (exampleValue.Elements != null && exampleValue.Elements.Any())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@
using AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions;
using AutoRest.CSharp.Common.Output.Expressions.ValueExpressions;
using AutoRest.CSharp.Generation.Types;
using AutoRest.CSharp.Output.Builders;
using AutoRest.CSharp.Output.Models.Serialization;
using AutoRest.CSharp.Output.Models.Types;
using AutoRest.CSharp.Output.Samples.Models;
using AutoRest.CSharp.Utilities;
using Azure;
using Azure.Core;
using Azure.ResourceManager.Models;
using Microsoft.CodeAnalysis.CSharp;
using static AutoRest.CSharp.Common.Output.Models.Snippets;

namespace AutoRest.CSharp.LowLevel.Extensions
namespace AutoRest.CSharp.Common.Output.Models.Samples
{
internal static partial class ExampleValueSnippets
{
Expand Down Expand Up @@ -188,13 +190,35 @@ private static ValueExpression GetExpressionForFrameworkType(Type frameworkType,
return Null.CastTo(frameworkType);
}

return frameworkType.IsValueType ? Default.CastTo(frameworkType) : Null.CastTo(frameworkType);
// TODO -- this might be an issue. We have so many shared common types in resoucemanager which replace the generated types in a library.
// This way is only temporary, we need a universal way to handle those replaced types.
if (frameworkType == typeof(ManagedServiceIdentityType))
{
if (exampleValue is InputExampleRawValue rawValue && rawValue.RawValue is string str)
{
return Literal(str);
}

return Default.CastTo(frameworkType);
}

if (frameworkType == typeof(UserAssignedIdentity))
{
return New.Instance(frameworkType);
}

return DefaultOf(frameworkType);
}

public static ValueExpression GetExpression(InputExampleParameterValue exampleParameterValue, SerializationFormat serializationFormat)
public static ValueExpression GetExpression(CSharpType type, InputExampleValue? value)
=> value != null ?
GetExpression(type, value, SerializationBuilder.GetDefaultSerializationFormat(type)) :
DefaultOf(type);

public static ValueExpression GetExpression(ExampleParameterValue exampleParameterValue, SerializationFormat serializationFormat)
{
if (exampleParameterValue.Value != null)
return GetExpression(exampleParameterValue.Type, exampleParameterValue.Value, serializationFormat);
return GetExpression(exampleParameterValue.Type, exampleParameterValue.Value, serializationFormat == SerializationFormat.Default ? SerializationBuilder.GetDefaultSerializationFormat(exampleParameterValue.Type) : serializationFormat);
else if (exampleParameterValue.Expression != null)
return exampleParameterValue.Expression;
else
Expand Down Expand Up @@ -373,12 +397,12 @@ private static ValueExpression GetExpressionForObjectType(ObjectType objectType,
if (valueDict.TryGetValue(property.InputModelProperty!.SerializedName, out var exampleValue))
{
properties.Remove(property);
argument = GetExpression(propertyType, exampleValue, property.SerializationFormat, includeCollectionInitialization: true);
argument = GetExpression(propertyType, exampleValue, GetSerializationFormat(property, propertyType), includeCollectionInitialization: true);
}
else
{
// if no match, we put default here
argument = propertyType.IsValueType && !propertyType.IsNullable ? Default : Null;
argument = DefaultOf(propertyType);
}
arguments.Add(argument);
}
Expand All @@ -390,13 +414,24 @@ private static ValueExpression GetExpressionForObjectType(ObjectType objectType,
foreach (var (property, exampleValue) in propertiesToWrite)
{
// we need to pass in the current type of this property to make sure its initialization is correct
var propertyExpression = GetExpression(property.Declaration.Type, exampleValue, property.SerializationFormat, includeCollectionInitialization: false);
var propertyExpression = GetExpression(property.Declaration.Type, exampleValue, GetSerializationFormat(property, property.Declaration.Type), includeCollectionInitialization: false);
initializerDict.Add(property.Declaration.Name, propertyExpression);
}
objectPropertyInitializer = new(initializerDict, false);
}

return new NewInstanceExpression(objectType.Type, arguments, objectPropertyInitializer);

static SerializationFormat GetSerializationFormat(ObjectTypeProperty property, CSharpType propertyType)
{
var serializationFormat = property.SerializationFormat; // this works for typespec input models
// TODO - wait for fix. For swagger input models, the serialization format is not properly added onto the property, therefore here we have to find the serialization format again
if (serializationFormat == SerializationFormat.Default)
{
serializationFormat = SerializationBuilder.GetDefaultSerializationFormat(propertyType);
}
return serializationFormat;
}
}

private static IReadOnlyDictionary<ObjectTypeProperty, InputExampleValue> GetPropertiesToWrite(IEnumerable<ObjectTypeProperty> properties, IReadOnlyDictionary<string, InputExampleValue> valueDict)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions;
using AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions.Azure;
using AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions.System;
using AutoRest.CSharp.Common.Output.Expressions.Statements;
using AutoRest.CSharp.Common.Output.Expressions.ValueExpressions;
using AutoRest.CSharp.Generation.Types;
Expand Down
3 changes: 0 additions & 3 deletions src/AutoRest.CSharp/Common/Output/Expressions/Snippets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using AutoRest.CSharp.Common.Input;
using AutoRest.CSharp.Common.Output.Expressions;
using AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions;
Expand All @@ -14,7 +12,6 @@
using AutoRest.CSharp.Generation.Types;
using AutoRest.CSharp.Generation.Writers;
using AutoRest.CSharp.Output.Models.Types;
using static AutoRest.CSharp.Common.Input.Configuration;

namespace AutoRest.CSharp.Common.Output.Models
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@

namespace AutoRest.CSharp.Common.Output.Expressions.Statements
{
internal record InvokeInstanceMethodStatement(ValueExpression? InstanceReference, string MethodName, IReadOnlyList<ValueExpression> Arguments, bool CallAsAsync) : MethodBodyStatement
internal record InvokeInstanceMethodStatement(ValueExpression? InstanceReference, string MethodName, IReadOnlyList<ValueExpression> Arguments, bool CallAsAsync, bool AddConfigureAwaitFalse = true) : MethodBodyStatement
{
public InvokeInstanceMethodStatement(ValueExpression? instance, string methodName) : this(instance, methodName, Array.Empty<ValueExpression>(), false) { }
public InvokeInstanceMethodStatement(ValueExpression? instance, string methodName, ValueExpression arg) : this(instance, methodName, new[] { arg }, false) { }
public InvokeInstanceMethodStatement(ValueExpression? instance, string methodName, ValueExpression arg1, ValueExpression arg2) : this(instance, methodName, new[] { arg1, arg2 }, false) { }
public InvokeInstanceMethodStatement(ValueExpression? instance, string methodName, ValueExpression arg1, ValueExpression arg2, ValueExpression arg3) : this(instance, methodName, new[] { arg1, arg2, arg3 }, false) { }

public InvokeInstanceMethodStatement(InvokeInstanceMethodExpression expression) : this(expression.InstanceReference, expression.MethodName, expression.Arguments, expression.CallAsAsync, expression.AddConfigureAwaitFalse) { }

public sealed override void Write(CodeWriter writer)
{
new InvokeInstanceMethodExpression(InstanceReference, MethodName, Arguments, null, CallAsAsync).Write(writer);
new InvokeInstanceMethodExpression(InstanceReference, MethodName, Arguments, null, CallAsAsync, AddConfigureAwaitFalse).Write(writer);
writer.LineRaw(";");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ internal record SingleLineCommentStatement(FormattableString Message) : MethodBo
{
public SingleLineCommentStatement(string message) : this(FormattableStringHelpers.FromString(message))
{ }

public override void Write(CodeWriter writer)
{
writer.Line($"// {Message}");
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using AutoRest.CSharp.Common.Input.Examples;
using AutoRest.CSharp.Common.Output.Expressions.ValueExpressions;
using AutoRest.CSharp.Generation.Types;
using AutoRest.CSharp.Input;
using AutoRest.CSharp.Output.Models.Requests;
using AutoRest.CSharp.Output.Models.Shared;

namespace AutoRest.CSharp.MgmtTest.Models
namespace AutoRest.CSharp.Output.Samples.Models
{
/// <summary>
/// A <see cref="ExampleParameterValue"/> represents a value for a parameter, which could either be a <see cref="ExampleValue"/>, or a <see cref="FormattableString"/> as a literal
/// A <see cref="ExampleParameterValue"/> represents a value for a parameter, which could either be a <see cref="InputExampleValue"/>, or a <see cref="ValueExpression"/> as an expression
/// </summary>
/// <param name="Parameter"></param>
/// <param name="Value"></param>
/// <param name="RawValue"></param>
internal record ExampleParameterValue
{
public string Name { get; }
Expand All @@ -24,7 +20,7 @@ internal record ExampleParameterValue

public InputExampleValue? Value { get; }

public FormattableString? Expression { get; }
public ValueExpression? Expression { get; }

private ExampleParameterValue(string name, CSharpType type)
{
Expand All @@ -37,19 +33,19 @@ public ExampleParameterValue(Reference reference, InputExampleValue value) : thi
Value = value;
}

public ExampleParameterValue(Reference reference, FormattableString rawValue) : this(reference.Name, reference.Type)
public ExampleParameterValue(Reference reference, ValueExpression expression) : this(reference.Name, reference.Type)
{
Expression = rawValue;
Expression = expression;
}

public ExampleParameterValue(Parameter parameter, InputExampleValue value) : this(parameter.Name, parameter.Type)
{
Value = value;
}

public ExampleParameterValue(Parameter parameter, FormattableString rawValue) : this(parameter.Name, parameter.Type)
public ExampleParameterValue(Parameter parameter, ValueExpression expression) : this(parameter.Name, parameter.Type)
{
Expression = rawValue;
Expression = expression;
}
}
}
Loading

0 comments on commit 53fbd40

Please sign in to comment.