예제 #1
0
        public PropertyBasedMethodMock(MocklisTypesForSymbols typesForSymbols, INamedTypeSymbol classSymbol, INamedTypeSymbol interfaceSymbol,
                                       IMethodSymbol symbol, string mockMemberName, bool strict, bool veryStrict) : base(typesForSymbols, classSymbol, interfaceSymbol, symbol,
                                                                                                                         mockMemberName, strict, veryStrict)
        {
            var parametersBuilder   = new SingleTypeOrValueTupleBuilder(TypesForSymbols);
            var returnValuesBuilder = new SingleTypeOrValueTupleBuilder(TypesForSymbols);

            if (!symbol.ReturnsVoid)
            {
                returnValuesBuilder.AddReturnValue(symbol.ReturnType, symbol.ReturnTypeIsNullableOrOblivious());
            }

            foreach (var parameter in symbol.Parameters)
            {
                switch (parameter.RefKind)
                {
                case RefKind.Ref:
                {
                    parametersBuilder.AddParameter(parameter);
                    returnValuesBuilder.AddParameter(parameter);
                    break;
                }

                case RefKind.Out:
                {
                    returnValuesBuilder.AddParameter(parameter);
                    break;
                }

                case RefKind.In:
                {
                    parametersBuilder.AddParameter(parameter);
                    break;
                }

                case RefKind.None:
                {
                    parametersBuilder.AddParameter(parameter);
                    break;
                }
                }
            }

            ParametersType   = parametersBuilder.Build();
            ReturnValuesType = returnValuesBuilder.Build();

            var parameterTypeSyntax = ParametersType.BuildTypeSyntax();

            var returnValueTypeSyntax = ReturnValuesType.BuildTypeSyntax();

            if (returnValueTypeSyntax == null)
            {
                MockMemberType = parameterTypeSyntax == null
                    ? TypesForSymbols.ActionMethodMock()
                    : TypesForSymbols.ActionMethodMock(parameterTypeSyntax);
            }
            else
            {
                MockMemberType = parameterTypeSyntax == null
                    ? TypesForSymbols.FuncMethodMock(returnValueTypeSyntax)
                    : TypesForSymbols.FuncMethodMock(parameterTypeSyntax, returnValueTypeSyntax);
            }
        }
예제 #2
0
        protected MemberDeclarationSyntax ExplicitInterfaceMember()
        {
            var baseReturnType = Symbol.ReturnsVoid
                ? F.PredefinedType(F.Token(SyntaxKind.VoidKeyword))
                : TypesForSymbols.ParseTypeName(Symbol.ReturnType, Symbol.ReturnTypeIsNullableOrOblivious());
            var returnType = baseReturnType;

            if (Symbol.ReturnsByRef)
            {
                returnType = F.RefType(returnType);
            }
            else if (Symbol.ReturnsByRefReadonly)
            {
                returnType = F.RefType(returnType).WithReadOnlyKeyword(F.Token(SyntaxKind.ReadOnlyKeyword));
            }

            var mockedMethod = ExplicitInterfaceMemberMethodDeclaration(returnType);

            var memberMockInstance = ExplicitInterfaceMemberMemberMockInstance();

            ExpressionSyntax invocation = F.InvocationExpression(
                F.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                         memberMockInstance, F.IdentifierName("Call")))
                                          .WithExpressionsAsArgumentList(ParametersType.BuildArgumentListWithOriginalNames());

            // look at the return parameters. If we don't have any we can just make the call.
            // if we only have one and that's the return value, we can just return it.
            if (ReturnValuesType.Count == 0 ||
                ReturnValuesType.Count == 1 && ReturnValuesType[0].IsReturnValue)
            {
                if (Symbol.ReturnsByRef || Symbol.ReturnsByRefReadonly)
                {
                    invocation = TypesForSymbols.WrapByRef(invocation, baseReturnType);
                }

                mockedMethod = mockedMethod.WithExpressionBody(F.ArrowExpressionClause(invocation))
                               .WithSemicolonToken(F.Token(SyntaxKind.SemicolonToken));
            }
            // if we only have one and that's not a return value, we can just assign it to the out or ref parameter it corresponds to.
            else if (ReturnValuesType.Count == 1)
            {
                mockedMethod = mockedMethod.WithBody(F.Block(F.ExpressionStatement(F.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                                                                          F.IdentifierName(ReturnValuesType[0].OriginalName), invocation))));
            }
            else
            {
                // if we have more than one, put it in a temporary variable. (consider name clashes with method parameter names)
                var    x   = new Uniquifier(Symbol.Parameters.Select(m => m.Name));
                string tmp = x.GetUniqueName("tmp");

                var statements = new List <StatementSyntax>
                {
                    F.LocalDeclarationStatement(F.VariableDeclaration(F.IdentifierName("var")).WithVariables(
                                                    F.SingletonSeparatedList(F.VariableDeclarator(F.Identifier(tmp)).WithInitializer(F.EqualsValueClause(invocation)))))
                };

                // then for any out or ref parameters, set their values from the temporary variable.
                foreach (var rv in ReturnValuesType.Where(a => !a.IsReturnValue))
                {
                    statements.Add(F.ExpressionStatement(F.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                                                F.IdentifierName(rv.OriginalName),
                                                                                F.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, F.IdentifierName(tmp),
                                                                                                         F.IdentifierName(rv.TupleSafeName)))));
                }

                // finally, if there is a 'proper' return type, return the corresponding value from the temporary variable.
                foreach (var rv in ReturnValuesType.Where(a => a.IsReturnValue))
                {
                    ExpressionSyntax memberAccess = F.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, F.IdentifierName(tmp),
                                                                             F.IdentifierName(rv.TupleSafeName));

                    if (Symbol.ReturnsByRef || Symbol.ReturnsByRefReadonly)
                    {
                        memberAccess = TypesForSymbols.WrapByRef(memberAccess, baseReturnType);
                    }

                    statements.Add(F.ReturnStatement(memberAccess));
                }

                mockedMethod = mockedMethod.WithBody(F.Block(statements));
            }

            return(mockedMethod);
        }