private static string ReplaceInterfaceTokens(string template, InjectableType injectableType)
 {
     return(template
            .Replace("$InterfaceName$", injectableType.TypeName)
            .Replace("$InterfaceNameBase$", injectableType.TypeBaseName)
            .Replace("$InterfaceType$", injectableType.ToString())
            .Replace("$InterfaceMockName$", injectableType.MockName));
 }
        private static void WriteExplicitConstructor(StringBuilder builder, TestGenerationContext context, string currentIndent)
        {
            builder.Append($"new {context.ClassName}");

            if (context.ConstructorTypes.Count > 0)
            {
                builder.AppendLine("(");

                for (int i = 0; i < context.ConstructorTypes.Count; i++)
                {
                    string         mockReferenceStatement;
                    InjectableType constructorType = context.ConstructorTypes[i];
                    if (constructorType == null)
                    {
                        mockReferenceStatement = "TODO";
                    }
                    else
                    {
                        string template = StaticBoilerplateSettings.GetTemplate(context.MockFramework, TemplateType.MockObjectReference);
                        mockReferenceStatement = template
                                                 .Replace("$InterfaceName$", constructorType.TypeName)
                                                 .Replace("$InterfaceNameBase$", constructorType.TypeBaseName);
                    }

                    builder.Append($"{currentIndent}    {mockReferenceStatement}");

                    if (i < context.ConstructorTypes.Count - 1)
                    {
                        builder.AppendLine(",");
                    }
                }

                builder.Append(")");
            }
            else if (context.Properties.Count == 0)
            {
                builder.Append("()");
            }

            if (context.Properties.Count > 0)
            {
                builder.AppendLine();
                builder.AppendLine("{");

                foreach (InjectableProperty property in context.Properties)
                {
                    string template = StaticBoilerplateSettings.GetTemplate(context.MockFramework, TemplateType.MockObjectReference);
                    string mockReferenceStatement = template
                                                    .Replace("$InterfaceName$", property.TypeName)
                                                    .Replace("$InterfaceNameBase$", property.TypeBaseName);

                    builder.AppendLine($"{property.Name} = {mockReferenceStatement},");
                }

                builder.Append(@"}");
            }
        }
        // Works for both field declarations and initializations.
        private static void WriteFieldLines(StringBuilder builder, TestGenerationContext context, string template)
        {
            for (int i = 0; i < context.InjectedTypes.Count; i++)
            {
                InjectableType injectedType = context.InjectedTypes[i];
                string         line         = ReplaceInterfaceTokens(template, injectedType);

                builder.Append(line);

                if (i < context.InjectedTypes.Count - 1)
                {
                    builder.AppendLine();
                }
            }
        }
        // Works for both field declarations and initializations.
        private static void WriteFieldLines(StringBuilder builder, TestGenerationContext context, string template)
        {
            for (int i = 0; i < context.InjectedTypes.Count; i++)
            {
                InjectableType injectedType = context.InjectedTypes[i];
                string         line         = template
                                              .Replace("$InterfaceName$", injectedType.TypeName)
                                              .Replace("$InterfaceNameBase$", injectedType.TypeBaseName);

                builder.Append(line);

                if (i < context.InjectedTypes.Count - 1)
                {
                    builder.AppendLine();
                }
            }
        }
Пример #5
0
        private static InjectableType CreateInjectableType(SyntaxNode node, SemanticModel semanticModel, SymbolInfo?symbolInfo = null)
        {
            switch (node.Kind())
            {
            case SyntaxKind.IdentifierName:
                if (symbolInfo == null)
                {
                    symbolInfo = semanticModel.GetSymbolInfo(node);
                }

                return(new InjectableType(symbolInfo.Value.Symbol.Name, symbolInfo.Value.Symbol.ContainingNamespace.ToString()));

            case SyntaxKind.GenericName:
                if (symbolInfo == null)
                {
                    symbolInfo = semanticModel.GetSymbolInfo(node);
                }

                var injectableType = new InjectableType(symbolInfo.Value.Symbol.Name, symbolInfo.Value.Symbol.ContainingNamespace.ToString());

                SyntaxNode typeArgumentNode = node.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.TypeArgumentList);
                if (typeArgumentNode == null)
                {
                    throw new ArgumentException("Could not find type argument node for GenericName node.");
                }

                foreach (SyntaxNode genericArgumentNode in typeArgumentNode.ChildNodes())
                {
                    injectableType.GenericTypeArguments.Add(CreateInjectableType(genericArgumentNode, semanticModel));
                }

                return(injectableType);

            case SyntaxKind.PredefinedType:
            default:
                return(new InjectableType(node.ToString(), null));
            }
        }
        private string GenerateUnitTestContentsOld(
            string unitTestNamespace,
            string className,
            string classNamespace,
            IList <InjectableProperty> properties,
            IList <InjectableType> constructorTypes)
        {
            TestFramework testFramework = Utilities.FindTestFramework(this.SelectedProject.Project);
            MockFramework mockFramework = Utilities.FindMockFramework(this.SelectedProject.Project);

            if (mockFramework == MockFramework.Unknown)
            {
                mockFramework = MockFramework.Moq;
            }

            string pascalCaseShortClassName = null;

            foreach (string suffix in ClassSuffixes)
            {
                if (className.EndsWith(suffix))
                {
                    pascalCaseShortClassName = suffix;
                    break;
                }
            }

            if (pascalCaseShortClassName == null)
            {
                pascalCaseShortClassName = className;
            }

            string classVariableName = pascalCaseShortClassName.Substring(0, 1).ToLowerInvariant() + pascalCaseShortClassName.Substring(1);

            List <InjectableType> injectedTypes = new List <InjectableType>(properties);

            injectedTypes.AddRange(constructorTypes.Where(t => t != null));

            var mockFields = new List <MockField>();

            foreach (InjectableType injectedType in injectedTypes)
            {
                mockFields.Add(
                    new MockField(
                        mockFramework == MockFramework.SimpleStubs ? "stub" + injectedType.TypeBaseName : "mock" + injectedType.TypeBaseName,
                        mockFramework == MockFramework.SimpleStubs ? "Stub" + injectedType.TypeName : injectedType.TypeName));
            }

            List <string> namespaces = new List <string>();

            namespaces.AddRange(MockFrameworkAbstraction.GetUsings(mockFramework));
            namespaces.Add(TestFrameworkAbstraction.GetUsing(testFramework));
            namespaces.Add(classNamespace);
            namespaces.AddRange(injectedTypes.Select(t => t.TypeNamespace));
            namespaces = namespaces.Distinct().ToList();
            namespaces.Sort(StringComparer.Ordinal);

            StringBuilder builder = new StringBuilder();

            foreach (string ns in namespaces)
            {
                builder.AppendLine($"using {ns};");
            }

            builder.Append(
                Environment.NewLine +
                "namespace ");

            builder.Append(unitTestNamespace);
            builder.Append(
                Environment.NewLine +
                "{" + Environment.NewLine +
                $"[{TestFrameworkAbstraction.GetTestClassAttribute(testFramework)}]" + Environment.NewLine +
                "public class ");
            builder.Append(className);
            builder.Append(
                "Tests" + Environment.NewLine +
                "{" + Environment.NewLine);
            if (mockFramework == MockFramework.Moq)
            {
                builder.Append("private MockRepository mockRepository;" + Environment.NewLine);

                if (mockFields.Count > 0)
                {
                    builder.AppendLine();
                }
            }

            foreach (MockField field in mockFields)
            {
                if (mockFramework == MockFramework.SimpleStubs)
                {
                    builder.AppendLine($"private {field.TypeName} {field.Name};");
                }
                else
                {
                    builder.AppendLine($"private Mock<{field.TypeName}> {field.Name};");
                }
            }

            builder.Append(
                Environment.NewLine +
                $"[{TestFrameworkAbstraction.GetTestInitializeAttribute(testFramework)}]" + Environment.NewLine +
                "public void TestInitialize()" + Environment.NewLine +
                "{" + Environment.NewLine);

            if (mockFramework == MockFramework.Moq)
            {
                builder.AppendLine("this.mockRepository = new MockRepository(MockBehavior.Strict);");

                if (mockFields.Count > 0)
                {
                    builder.AppendLine();
                }
            }

            foreach (MockField field in mockFields)
            {
                string fieldCreationStatement;

                if (mockFramework == MockFramework.SimpleStubs)
                {
                    fieldCreationStatement = $"new {field.TypeName}()";
                }
                else
                {
                    fieldCreationStatement = $"this.mockRepository.Create<{field.TypeName}>()";
                }

                builder.AppendLine($"this.{field.Name} = {fieldCreationStatement};");
            }

            builder.Append(
                "}" + Environment.NewLine +
                Environment.NewLine);

            if (mockFramework == MockFramework.Moq)
            {
                builder.Append(
                    $"[{TestFrameworkAbstraction.GetTestCleanupAttribute(testFramework)}]" + Environment.NewLine +
                    "public void TestCleanup()" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "this.mockRepository.VerifyAll();" + Environment.NewLine +
                    "}" + Environment.NewLine +
                    Environment.NewLine);
            }

            builder.Append(
                $"[{TestFrameworkAbstraction.GetTestMethodAttribute(testFramework)}]" + Environment.NewLine +
                "public void TestMethod1()" + Environment.NewLine +
                "{" + Environment.NewLine +
                "" + Environment.NewLine +
                "" + Environment.NewLine);

            builder.AppendLine($"{className} {classVariableName} = this.Create{pascalCaseShortClassName}();");
            builder.AppendLine("");
            builder.AppendLine("");
            builder.AppendLine("}");
            builder.AppendLine();
            builder.AppendLine($"private {className} Create{pascalCaseShortClassName}()");
            builder.AppendLine("{");
            builder.Append($"return new {className}");

            if (constructorTypes.Count > 0)
            {
                builder.AppendLine("(");

                for (int i = 0; i < constructorTypes.Count; i++)
                {
                    string         mockReferenceStatement;
                    InjectableType constructorType = constructorTypes[i];
                    if (constructorType == null)
                    {
                        mockReferenceStatement = "TODO";
                    }
                    else if (mockFramework == MockFramework.SimpleStubs)
                    {
                        mockReferenceStatement = $"this.stub{constructorType.TypeBaseName}";
                    }
                    else
                    {
                        mockReferenceStatement = $"this.mock{constructorType.TypeBaseName}.Object";
                    }

                    builder.Append($"    {mockReferenceStatement}");

                    if (i < constructorTypes.Count - 1)
                    {
                        builder.AppendLine(",");
                    }
                }

                builder.Append(")");
            }
            else if (properties.Count == 0)
            {
                builder.Append("()");
            }

            if (properties.Count > 0)
            {
                builder.AppendLine();
                builder.AppendLine("{");

                foreach (InjectableProperty property in properties)
                {
                    string mockReferenceStatement;
                    if (mockFramework == MockFramework.SimpleStubs)
                    {
                        mockReferenceStatement = $"this.stub{property.TypeBaseName}";
                    }
                    else
                    {
                        mockReferenceStatement = $"this.mock{property.TypeBaseName}.Object";
                    }

                    builder.AppendLine($"{property.Name} = {mockReferenceStatement},");
                }

                builder.Append(@"}");
            }

            builder.AppendLine(";");
            builder.AppendLine("}");
            builder.AppendLine("}");
            builder.AppendLine("}");

            SyntaxTree tree          = CSharpSyntaxTree.ParseText(builder.ToString());
            SyntaxNode formattedNode = Formatter.Format(tree.GetRoot(), CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace);

            return(formattedNode.ToString());

            //return builder.ToString();
        }
        private async Task <string> GenerateUnitTestContentsFromFileAsync(string inputFilePath)
        {
            Microsoft.CodeAnalysis.Solution solution = CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace.CurrentSolution;
            DocumentId documentId = solution.GetDocumentIdsWithFilePath(inputFilePath).FirstOrDefault();

            if (documentId == null)
            {
                this.HandleError("Could not find document in solution with file path " + inputFilePath);
            }

            var document = solution.GetDocument(documentId);

            SyntaxNode root = await document.GetSyntaxRootAsync();

            SemanticModel semanticModel = await document.GetSemanticModelAsync();

            SyntaxNode firstClassDeclaration = root.DescendantNodes().FirstOrDefault(node => node.Kind() == SyntaxKind.ClassDeclaration);

            if (firstClassDeclaration == null)
            {
                this.HandleError("Could not find class declaration.");
            }

            if (firstClassDeclaration.ChildTokens().Any(node => node.Kind() == SyntaxKind.AbstractKeyword))
            {
                this.HandleError("Cannot unit test an abstract class.");
            }

            SyntaxToken classIdentifierToken = firstClassDeclaration.ChildTokens().FirstOrDefault(n => n.Kind() == SyntaxKind.IdentifierToken);

            if (classIdentifierToken == null)
            {
                this.HandleError("Could not find class identifier.");
            }

            NamespaceDeclarationSyntax namespaceDeclarationSyntax = null;

            if (!Utilities.TryGetParentSyntax(firstClassDeclaration, out namespaceDeclarationSyntax))
            {
                this.HandleError("Could not find class namespace.");
            }

            MockFramework mockFramework = Utilities.FindMockFramework(this.SelectedProject.Project);
            TestFramework testFramework = Utilities.FindTestFramework(this.SelectedProject.Project);

            // Find property injection types
            var injectableProperties = new List <InjectableProperty>();

            string           classFullName = namespaceDeclarationSyntax.Name + "." + classIdentifierToken;
            INamedTypeSymbol classType     = semanticModel.Compilation.GetTypeByMetadataName(classFullName);

            foreach (ISymbol member in classType.GetBaseTypesAndThis().SelectMany(n => n.GetMembers()))
            {
                if (member.Kind == SymbolKind.Property)
                {
                    IPropertySymbol property = (IPropertySymbol)member;

                    foreach (AttributeData attribute in property.GetAttributes())
                    {
                        if (PropertyInjectionAttributeNames.Contains(attribute.AttributeClass.ToString()))
                        {
                            var injectableProperty = InjectableProperty.TryCreateInjectableProperty(property.Name, property.Type.ToString(), mockFramework);
                            if (injectableProperty != null)
                            {
                                injectableProperties.Add(injectableProperty);
                            }
                        }
                    }
                }
            }

            this.className = classIdentifierToken.ToString();

            // Find constructor injection types
            var        constructorInjectionTypes = new List <InjectableType>();
            SyntaxNode constructorDeclaration    = firstClassDeclaration.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.ConstructorDeclaration);

            if (constructorDeclaration != null)
            {
                SyntaxNode parameterListNode = constructorDeclaration.ChildNodes().First(n => n.Kind() == SyntaxKind.ParameterList);
                var        parameterNodes    = parameterListNode.ChildNodes().Where(n => n.Kind() == SyntaxKind.Parameter);

                foreach (SyntaxNode node in parameterNodes)
                {
                    constructorInjectionTypes.Add(InjectableType.TryCreateInjectableTypeFromParameterNode(node, semanticModel, mockFramework));
                }
            }

            string unitTestNamespace;
            string defaultNamespace = this.SelectedProject.Project.Properties.Item("DefaultNamespace").Value as string;

            if (string.IsNullOrEmpty(this.relativePath))
            {
                unitTestNamespace = defaultNamespace;
            }
            else
            {
                List <string> defaultNamespaceParts  = defaultNamespace.Split('.').ToList();
                List <string> unitTestNamespaceParts = new List <string>(defaultNamespaceParts);
                unitTestNamespaceParts.AddRange(this.relativePath.Split('\\'));

                unitTestNamespace = string.Join(".", unitTestNamespaceParts);
            }

            List <InjectableType> injectedTypes = new List <InjectableType>(injectableProperties);

            injectedTypes.AddRange(constructorInjectionTypes.Where(t => t != null));

            GenerateMockNames(injectedTypes);

            // Compile information needed to generate the test
            var context = new TestGenerationContext(
                mockFramework,
                testFramework,
                unitTestNamespace,
                this.className,
                namespaceDeclarationSyntax.Name.ToString(),
                injectableProperties,
                constructorInjectionTypes,
                injectedTypes);

            return(this.GenerateUnitTestContents(context));
        }