Exemple #1
0
        private static Tuple <Node, string> GenerateTypeForParamsUnmarshal(MethodGo mg)
        {
            var typeName = $"{mg.Name}Params";
            var fields   = new List <StructFieldDef>();

            fields.Add(new StructFieldDef("SubscriptionID", "string", "json:\"subscriptionId\""));

            if (mg.LocalParameters.Any())
            {
                foreach (var param in mg.LocalParameters)
                {
                    string fieldTypeName = null;
                    if (param.ModelType is PrimaryTypeGo)
                    {
                        fieldTypeName = param.ModelTypeName;
                    }
                    else if (param.ModelType is CompositeTypeGo)
                    {
                        fieldTypeName = $"{mg.CodeModel.Namespace}.{param.ModelTypeName}";
                    }
                    else if (param.ModelType is SequenceTypeGo)
                    {
                        var st = param.ModelType as SequenceTypeGo;
                        if (st.ElementType is PrimaryTypeGo || st.ElementType is EnumTypeGo)
                        {
                            fieldTypeName = $"[]{st.ElementType.Name}";
                        }
                        else
                        {
                            fieldTypeName = $"[]{mg.CodeModel.Namespace}.{st.ElementType.Name}";
                        }
                    }
                    else if (param.ModelType is EnumTypeGo)
                    {
                        // TODO
                        fieldTypeName = $"{mg.CodeModel.Namespace}.{param.ModelTypeName}";
                    }
                    else
                    {
                        throw new NotImplementedException($"support for param type {param.ModelType} NYI");
                    }

                    fields.Add(new StructFieldDef(param.Name.ToString().Capitalize(), fieldTypeName, $"json:\"{param.SerializedName}\""));
                    TypeAddedEvent?.Invoke(param.ModelType);
                }
            }

            fields.Add(new StructFieldDef(ReservedParamsFieldName, "testrt.ReservedParams", "json:\"__reserved\""));
            var structDef = StructDefinition.Generate(typeName, fields);

            return(new Tuple <Node, string>(structDef, typeName));
        }
Exemple #2
0
        private static IReadOnlyList <FuncCallParam> GenerateApiCallParams(MethodGo mg, string unmarshalVar)
        {
            // use mg.LocalParameters instead of Parameters so that the
            // subscription ID and API version params (and possibly others)
            // are omitted as they are part of the client.
            if (!mg.LocalParameters.Any())
            {
                return(null);
            }

            var funcCallParams = new List <FuncCallParam>();

            // the go generator places parameters that aren't required at the end
            // TODO: expose this in the generator so we don't have to duplicate the logic
            var paramsList = mg.LocalParameters.OrderBy(p => !p.IsRequired).ToList();

            foreach (var param in paramsList)
            {
                TypeModifier typeMod = TypeModifier.ByReference;
                if (param.IsRequired || param.ModelType.CanBeEmpty())
                {
                    typeMod = TypeModifier.ByValue;
                }

                funcCallParams.Add(new FuncCallParam(new Identifier($"{unmarshalVar}.{param.Name.ToString().Capitalize()}"), typeMod));
            }

            // if this is a long-running operation there will be an optional channel
            // parameter at the end of the parameter list, pass nil for this one.
            if (mg.IsLongRunningOperation())
            {
                funcCallParams.Add(new FuncCallParam(new Nil(), TypeModifier.ByValue));
            }

            return(funcCallParams);
        }
 /// <summary>
 /// Returns the page type name for the specified method, which is the type to
 /// be returned from the method (this is applicable to paged operations).
 /// </summary>
 /// <param name="method">The paged operation.</param>
 /// <returns>The name of the type to be returned from the specified method.</returns>
 internal string GetPageTypeName(MethodGo method)
 {
     return($"{method.MethodReturnType()}Page");
 }
 /// <summary>
 /// Returns the future type name for the specified method, which is the type to
 /// be returned from the method (this is applicable to long-running operations).
 /// </summary>
 /// <param name="method">The long-running operation.</param>
 /// <returns>The name of the type to be returned from the specified method.</returns>
 internal string GetFutureTypeName(MethodGo method)
 {
     // operation group + method name is guaranteed to be unique
     return(GetFutureTypeName($"{method.Group}{method.Name}"));
 }
Exemple #5
0
        /// <summary>
        /// Generates a test case function for the specified method.
        /// </summary>
        /// <param name="mg">The method for which a test case will be generated.</param>
        /// <param name="rpcTypeName">The type name use for RPC dispatch.</param>
        /// <returns>The root node in this test case function AST.</returns>
        public static Tuple <Node, string> Generate(MethodGo mg, string rpcTypeName, string replyTypeName, string replyConvFuncName, string loggerVarName)
        {
            if (mg == null)
            {
                throw new ArgumentNullException(nameof(mg));
            }

            if (string.IsNullOrWhiteSpace(replyTypeName))
            {
                throw new ArgumentException(nameof(replyTypeName));
            }

            if (string.IsNullOrWhiteSpace(replyConvFuncName))
            {
                throw new ArgumentException(nameof(replyConvFuncName));
            }

            var errorVar     = "err";
            var jsonParamVar = "parameters";
            var replyVar     = "reply";

            var operationId = mg.SerializedName.ToString();

            if (!char.IsUpper(operationId[0]))
            {
                operationId = $"{char.ToUpperInvariant(operationId[0])}{operationId.Substring(1)}";
            }

            var rpcTypeVar = char.ToLowerInvariant(rpcTypeName[0]).ToString();

            var func = FunctionSignature.Generate(new FuncParamSig(rpcTypeVar, TypeModifier.ByReference, rpcTypeName),
                                                  operationId, new[]
            {
                new FuncParamSig(jsonParamVar, TypeModifier.ByValue, "json.RawMessage"),
                new FuncParamSig(replyVar, TypeModifier.ByReference, replyTypeName)
            }, new[]
            {
                new FuncReturnSig(null, TypeModifier.ByValue, "error")
            });

            var funcBody = new OpenDelimiter(BinaryDelimiterType.Brace);

            // generate a type used to unmarshal the parameters
            string unmarshalVar  = null;
            var    unmarshalType = GenerateTypeForParamsUnmarshal(mg);

            funcBody.AddChild(unmarshalType.Item1);
            funcBody.AddChild(new Terminal());

            unmarshalVar = unmarshalType.Item2.ToLowerInvariant();

            // do the unmarshaling and return on failure
            funcBody.AddChild(VariableDecl.Generate(unmarshalVar, unmarshalType.Item2));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign, new Identifier(errorVar),
                                                        FunctionCall.Generate("json.Unmarshal", new[]
            {
                new FuncCallParam(new Identifier(jsonParamVar), TypeModifier.ByValue),
                new FuncCallParam(new Identifier(unmarshalVar), TypeModifier.ByReference)
            })));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(ErrorCheck.Generate(errorVar, OnError.ReturnError));
            funcBody.AddChild(new Terminal());

            var authVar = "auth";

            funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign,
                                                        DelimitedSequence.Generate(UnaryDelimiterType.Comma, new[]
            {
                new Identifier(authVar),
                new Identifier(errorVar)
            }),
                                                        FunctionCall.Generate($"{unmarshalVar}.{ReservedParamsFieldName}.Credentials.CreateBearerAuthorizer", null)));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(ErrorCheck.Generate(errorVar, OnError.ReturnError));
            funcBody.AddChild(new Terminal());

            // create the client and call the target function
            var clientVar = "client";

            // check if the client ctor has any parameters
            List <FuncCallParam> clientParams = null;

            if (!string.IsNullOrWhiteSpace(((MethodGroupGo)mg.MethodGroup).GlobalParameters))
            {
                clientParams = new List <FuncCallParam>();
                var globalParams = ((MethodGroupGo)mg.MethodGroup).GlobalParameters.Split(new[] { ',' });

                // each param is the var name followed by the type name, e.g. "subscriptionID string"
                foreach (var globalParam in globalParams)
                {
                    var paramName = globalParam.Substring(0, globalParam.IndexOf(' '));
                    clientParams.Add(new FuncCallParam(new Identifier($"{unmarshalVar}.{paramName.Capitalize()}"), TypeModifier.ByValue));
                }
            }

            funcBody.AddChild(FunctionCall.Generate($"{loggerVarName}.Println", new[]
            {
                new FuncCallParam(new Literal <string>(operationId), TypeModifier.ByValue)
            }));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(FunctionCall.Generate($"{loggerVarName}.Printf", new[]
            {
                new FuncCallParam(new Literal <string>("received %v\\n"), TypeModifier.ByValue),
                new FuncCallParam(new Identifier(unmarshalVar), TypeModifier.ByValue)
            }));
            funcBody.AddChild(new Terminal());

            // the client creation function name prefix is hard-coded in the Go generator
            var clientCtorName = $"{mg.CodeModel.Namespace}.New";

            if (!string.IsNullOrWhiteSpace(mg.MethodGroup.Name))
            {
                clientCtorName = $"{clientCtorName}{((MethodGroupGo)mg.MethodGroup).ClientName}";
            }

            funcBody.AddChild(BinaryOpSequence.Generate(
                                  BinaryOperatorType.DeclareAndAssign,
                                  new Identifier(clientVar),
                                  FunctionCall.Generate(clientCtorName, clientParams)));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.Assignment,
                                                        new Identifier($"{clientVar}.Authorizer"), new Identifier(authVar)));
            funcBody.AddChild(new Terminal());

            var rChanVar       = "rChan";
            var eChanVar       = "eChan";
            var responseVar    = "resp";
            var rawResponseVar = "rawResp";

            var isLro = mg.IsLongRunningOperation() && !mg.IsPageable;

            funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign,
                                                        DelimitedSequence.Generate(UnaryDelimiterType.Comma, new[]
            {
                new Identifier(isLro ? rChanVar : responseVar),
                new Identifier(isLro ? eChanVar : errorVar)
            }),
                                                        FunctionCall.Generate($"{clientVar}.{mg.Name}", GenerateApiCallParams(mg, unmarshalVar))));
            funcBody.AddChild(new Terminal());

            if (isLro)
            {
                funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.Assignment,
                                                            new Identifier(errorVar), new Identifier($"<-{eChanVar}")));
                funcBody.AddChild(new Terminal());
            }

            funcBody.AddChild(ErrorCheck.Generate(errorVar, OnError.ReturnError));
            funcBody.AddChild(new Terminal());

            if (isLro)
            {
                funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign,
                                                            new Identifier(responseVar), new Identifier($"<-{rChanVar}")));
                funcBody.AddChild(new Terminal());
            }

            funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.DeclareAndAssign,
                                                        DelimitedSequence.Generate(UnaryDelimiterType.Comma, new[]
            {
                new Identifier(rawResponseVar),
                new Identifier(errorVar)
            }),
                                                        FunctionCall.Generate(replyConvFuncName, new[]
            {
                new FuncCallParam(new Identifier(mg.HasReturnValue() ? $"{responseVar}.Response" : $"{responseVar}"), TypeModifier.ByReference),
                new FuncCallParam(mg.HasReturnValue() ? (Node) new Identifier(responseVar) : new Nil(), TypeModifier.ByValue)
            })));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(FunctionCall.Generate($"{loggerVarName}.Printf", new[]
            {
                new FuncCallParam(new Literal <string>("response %v\\n"), TypeModifier.ByValue),
                new FuncCallParam(new Identifier($"*{rawResponseVar}"), TypeModifier.ByValue)
            }));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(BinaryOpSequence.Generate(BinaryOperatorType.Assignment,
                                                        new Identifier($"*{replyVar}"), new Identifier($"*{rawResponseVar}")));
            funcBody.AddChild(new Terminal());

            funcBody.AddChild(ReturnStatement.Generate(new[]
            {
                errorVar
            }));

            funcBody.AddClosingDelimiter();
            func.AddChild(funcBody);
            return(new Tuple <Node, string>(func, operationId));
        }