Beispiel #1
0
        public async void Execute(ISolution solution, ITextControl textControl)
        {
            if (this.ExistingProjectFile != null)
            {
                await ShowProjectFile(solution, this.ExistingProjectFile, null);

                return;
            }

            using (ReadLockCookie.Create())
            {
                string         testClassName;
                string         testNamespace;
                string         testFileName;
                IProjectFolder testFolder;
                Template       testFileTemplate;

                using (var cookie = solution.CreateTransactionCookie(DefaultAction.Rollback, this.Text, NullProgressIndicator.Create()))
                {
                    var declaration = this._provider.GetSelectedElement <ICSharpTypeDeclaration>();

                    var declaredType = declaration?.DeclaredElement;
                    if (declaredType == null)
                    {
                        return;
                    }

                    var settingsStore  = declaration.GetSettingsStore();
                    var helperSettings = ReSharperHelperSettings.GetSettings(settingsStore);

                    var testProject = this.CachedTestProject ?? this.ResolveTargetTestProject(declaration, solution, helperSettings);
                    if (testProject == null)
                    {
                        return;
                    }

                    var classNamespaceParts = TrimDefaultProjectNamespace(declaration.GetProject().NotNull(), declaredType.GetContainingNamespace().QualifiedName);
                    var testFolderLocation  = classNamespaceParts.Aggregate(testProject.Location, (current, part) => current.Combine(part));

                    testNamespace = StringUtil.MakeFQName(testProject.GetDefaultNamespace(), StringUtil.MakeFQName(classNamespaceParts));

                    testFolder = testProject.GetOrCreateProjectFolder(testFolderLocation, cookie);
                    if (testFolder == null)
                    {
                        return;
                    }

                    testClassName = declaredType.ShortName + helperSettings.TestClassNameSuffix;
                    testFileName  = testClassName + ".cs";

                    testFileTemplate = StoredTemplatesProvider.Instance.EnumerateTemplates(settingsStore, TemplateApplicability.File).FirstOrDefault(t => t.Description == TemplateDescription);

                    cookie.Commit(NullProgressIndicator.Create());
                }

                if (testFileTemplate != null)
                {
                    await FileTemplatesManager.Instance.CreateFileFromTemplateAsync(testFileName, new ProjectFolderWithLocation(testFolder), testFileTemplate);

                    return;
                }

                var newFile = AddNewItemHelper.AddFile(testFolder, testFileName);
                if (newFile == null)
                {
                    return;
                }

                int?caretPosition = -1;
                solution.GetPsiServices()
                .Transactions.Execute(this.Text, () =>
                {
                    var psiSourceFile = newFile.ToSourceFile();

                    var csharpFile = psiSourceFile?.GetDominantPsiFile <CSharpLanguage>() as ICSharpFile;
                    if (csharpFile == null)
                    {
                        return;
                    }

                    var elementFactory = CSharpElementFactory.GetInstance(csharpFile);

                    var namespaceDeclaration = elementFactory.CreateNamespaceDeclaration(testNamespace);
                    var addedNs = csharpFile.AddNamespaceDeclarationAfter(namespaceDeclaration, null);

                    var classLikeDeclaration = (IClassLikeDeclaration)elementFactory.CreateTypeMemberDeclaration("public class $0 {}", testClassName);
                    var addedTypeDeclaration = addedNs.AddTypeDeclarationAfter(classLikeDeclaration, null) as IClassDeclaration;

                    caretPosition = addedTypeDeclaration?.Body?.GetDocumentRange().TextRange.StartOffset + 1;
                });

                await ShowProjectFile(solution, newFile, caretPosition);
            }
        }
Beispiel #2
0
        public bool IsAvailable(IUserDataHolder cache)
        {
            this.ExistingProjectFile = null;
            this.CachedTestProject   = null;

            var classDeclaration = ClassDeclarationNavigator.GetByNameIdentifier(this._provider.GetSelectedElement <ICSharpIdentifier>());
            var declaredType     = classDeclaration?.DeclaredElement;

            if (declaredType == null)
            {
                return(false);
            }

            // Disable for nested classes.
            if (classDeclaration.GetContainingTypeDeclaration() != null)
            {
                return(false);
            }

            // TRY RESOLVE EXISTING TEST.
            var helperSettings = ReSharperHelperSettings.GetSettings(classDeclaration.GetSettingsStore());

            var testProject = this.CachedTestProject = this.ResolveTargetTestProject(classDeclaration, classDeclaration.GetSolution(), helperSettings);

            if (testProject == null)
            {
                return(false);
            }

            // Skip project if it's the same as current. This way we don't suggest to create tests in test projects.
            if (testProject.Equals(classDeclaration.GetProject()))
            {
                return(false);
            }

            var testClassNamespaceParts = MakeTestClassNamespaceParts(classDeclaration, testProject);

            if (testClassNamespaceParts == null)
            {
                return(false);
            }
            var testNamespace = StringUtil.MakeFQName(testClassNamespaceParts);

            // Resolve candidates for test classes.
            var validTestSuffixes = helperSettings.ValidTestClassNameSuffixes?.Split(',', StringSplitOptions.RemoveEmptyEntries)
                                    .Select(s => s.ToString())
                                    .Concat(helperSettings.TestClassNameSuffix)
                                    .Distinct();

            var classTypeFqnCandidates = validTestSuffixes?.Select(suffix => StringUtil.MakeFQName(testNamespace, declaredType.ShortName + suffix));

            if (classTypeFqnCandidates == null)
            {
                return(false);
            }

            var symbolsService = classDeclaration.GetPsiServices().Symbols;

            var testClass = testProject.GetPsiModules()
                            .Select(m => symbolsService.GetSymbolScope(m, false, true))
                            .SelectMany(scope => classTypeFqnCandidates.Select(scope.GetTypeElementByCLRName))
                            .FirstNotNull();

            this.ExistingProjectFile = testClass?.GetSingleOrDefaultSourceFile()?.ToProjectFile();

            return(true);
        }
Beispiel #3
0
        private IProject ResolveTargetTestProject([NotNull] ITreeNode contextNode, [NotNull] ISolution solution, [NotNull] ReSharperHelperSettings helperSettings)
        {
            // Get project by assembly attribute (if present).
            var projectName = solution.GetPsiServices()
                              .Symbols
                              .GetModuleAttributes(contextNode.GetPsiModule())
                              .GetAttributeInstances(AssemblyMetadataAttributeName, false)
                              .Select(TryExtractProjectNameFromAssemblyMetadataAttribute)
                              .FirstNotNull();

            // Check whether we have configured global test project.
            if (string.IsNullOrEmpty(projectName))
            {
                projectName = helperSettings.TestsProjectName;
            }

            if (!string.IsNullOrEmpty(projectName))
            {
                return(solution.GetProjectByName(projectName));
            }

            // Try to guess project specific test project.
            var currentProjectName = contextNode.GetProject()?.Name;

            if (currentProjectName == null)
            {
                return(null);
            }

            var candidates = TestProjectSuffixes
                             .SelectMany(suffix => solution.GetProjectsByName(currentProjectName + suffix))
                             .WhereNotNull()
                             .ToArray();

            if (candidates.Length > 0)
            {
                if (candidates.Length == 1)
                {
                    return(candidates[0]);
                }

                return(null);
            }

            // Try to guess global test project.
            candidates = solution.GetAllProjects()
                         .Where(proj => TestProjectSuffixes.Any(suffix => proj.Name.EndsWith(suffix, StringComparison.Ordinal)))
                         .ToArray();

            if (candidates.Length == 1)
            {
                return(candidates[0]);
            }

            return(null);
        }
        private static string[] GetTestClassRelativeNamespaceParts([NotNull] ITypeDeclaration classDeclaration, [NotNull] IProject testProject, ReSharperHelperSettings helperSettings)
        {
            var currentProject = classDeclaration.GetProject();

            if (currentProject == null)
            {
                return(null);
            }

            var typeElement = classDeclaration.DeclaredElement;

            if (typeElement == null)
            {
                return(null);
            }

            var relativeSourceNsParts = TrimDefaultProjectNamespace(currentProject, typeElement.GetContainingNamespace().QualifiedName);

            if (!helperSettings.TestsProjectSubNamespace.IsNullOrEmpty())
            {
                string[] subDirParts = StringUtil.FullySplitFQName(helperSettings.TestsProjectSubNamespace);
                relativeSourceNsParts = subDirParts.Concat(relativeSourceNsParts).ToArray();
            }

            return(relativeSourceNsParts);
            //
            //
            // // IEnumerable<string> testProjectDefaultNsParts = StringUtil.FullySplitFQName(testProject.GetDefaultNamespace().NotNull());
            //
            // return testProjectDefaultNsParts.Concat(relativeTypeNamespace).ToArray();
        }