private static void WriteUsings(StringBuilder builder, TestGenerationContext context)
        {
            List <string> namespaces = new List <string>();

            namespaces.AddRange(MockFrameworkAbstraction.GetUsings(context.MockFramework));
            namespaces.Add(TestFrameworkAbstraction.GetUsing(context.TestFramework));
            namespaces.Add(context.ClassNamespace);

            foreach (InjectableType injectedType in context.InjectedTypes)
            {
                namespaces.AddRange(injectedType.TypeNamespaces);
            }

            namespaces = namespaces.Distinct().ToList();
            namespaces.Sort(StringComparer.Ordinal);

            for (int i = 0; i < namespaces.Count; i++)
            {
                builder.Append($"using {namespaces[i]};");

                if (i < namespaces.Count - 1)
                {
                    builder.AppendLine();
                }
            }
        }
        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();
                }
            }
        }
        private static void WriteMockFieldInitializations(StringBuilder builder, TestGenerationContext context)
        {
            string template = StaticBoilerplateSettings.GetTemplate(context.MockFramework, TemplateType.MockFieldInitialization);

            WriteFieldLines(builder, context, template);
        }
        private string GenerateUnitTestContents(TestGenerationContext context)
        {
            TestFramework testFramework = context.TestFramework;
            MockFramework mockFramework = context.MockFramework;

            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);

            string fileTemplate = StaticBoilerplateSettings.GetTemplate(mockFramework, TemplateType.File);
            var    builder      = new StringBuilder();

            for (int i = 0; i < fileTemplate.Length; i++)
            {
                char c = fileTemplate[i];
                if (c == '$')
                {
                    int endIndex = -1;
                    for (int j = i + 1; j < fileTemplate.Length; j++)
                    {
                        if (fileTemplate[j] == '$')
                        {
                            endIndex = j;
                            break;
                        }
                    }

                    if (endIndex < 0)
                    {
                        // We couldn't find the end index for the replacement property name. Continue.
                        builder.Append(c);
                    }
                    else
                    {
                        // Calculate values on demand from switch statement. Some are preset values, some need a bit of calc like base name,
                        // some are dependent on the test framework (attributes), some need to pull down other templates and loop through mock fields
                        string propertyName = fileTemplate.Substring(i + 1, endIndex - i - 1);
                        switch (propertyName)
                        {
                        case "UsingStatements":
                            WriteUsings(builder, context);
                            break;

                        case "Namespace":
                            builder.Append(context.UnitTestNamespace);
                            break;

                        case "MockFieldDeclarations":
                            WriteMockFieldDeclarations(builder, context);
                            break;

                        case "MockFieldInitializations":
                            WriteMockFieldInitializations(builder, context);
                            break;

                        case "ExplicitConstructor":
                            WriteExplicitConstructor(builder, context, FindIndent(fileTemplate, i));
                            break;

                        case "ClassName":
                            builder.Append(context.ClassName);
                            break;

                        case "ClassNameShort":
                            builder.Append(GetShortClassName(context.ClassName));
                            break;

                        case "ClassNameShortLower":
                            builder.Append(GetShortClassNameLower(context.ClassName));
                            break;

                        case "TestClassAttribute":
                            builder.Append(TestFrameworkAbstraction.GetTestClassAttribute(testFramework));
                            break;

                        case "TestInitializeAttribute":
                            builder.Append(TestFrameworkAbstraction.GetTestInitializeAttribute(testFramework));
                            break;

                        case "TestCleanupAttribute":
                            builder.Append(TestFrameworkAbstraction.GetTestCleanupAttribute(testFramework));
                            break;

                        case "TestMethodAttribute":
                            builder.Append(TestFrameworkAbstraction.GetTestMethodAttribute(testFramework));
                            break;

                        default:
                            // We didn't recognize it, just pass through.
                            builder.Append($"${propertyName}$");
                            break;
                        }

                        i = endIndex;
                    }
                }
                else
                {
                    builder.Append(c);
                }
            }

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

            return(formattedNode.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.");
            }

            // 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 (attribute.AttributeClass.ToString() == "Microsoft.Practices.Unity.DependencyAttribute")
                        {
                            injectableProperties.Add(new InjectableProperty(property.Name, property.Type.Name, property.Type.ContainingNamespace.ToString()));
                        }
                    }
                }
            }

            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)
                {
                    SyntaxNode identifierNode = node.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.IdentifierName);
                    if (identifierNode != null)
                    {
                        SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(identifierNode);

                        constructorInjectionTypes.Add(
                            new InjectableType(
                                symbolInfo.Symbol.Name,
                                symbolInfo.Symbol.ContainingNamespace.ToString()));
                    }
                    else
                    {
                        constructorInjectionTypes.Add(null);
                    }
                }
            }

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

            string projectName = this.SelectedProject.Project.Name;

            if (string.IsNullOrEmpty(defaultNamespace) || defaultNamespace[0] == '.')
            {
                defaultNamespace = projectName + defaultNamespace;
            }

            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));

            // Compile information needed to generate the test
            var context = new TestGenerationContext(
                Utilities.FindMockFramework(this.SelectedProject.Project),
                Utilities.FindTestFramework(this.SelectedProject.Project),
                unitTestNamespace,
                this.className,
                namespaceDeclarationSyntax.Name.ToString(),
                injectableProperties,
                constructorInjectionTypes,
                injectedTypes);

            return(this.GenerateUnitTestContents(context));
        }