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