// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using ICSharpCode.Core; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Parser; using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.UnitTesting { /// /// Manages the collection of TestProjects. /// sealed class TestSolution : TestBase, ITestSolution { readonly IResourceService resourceService; readonly ITestService testService; readonly List changeListeners = new List(); public TestSolution(ITestService testService, IResourceService resourceService) { if (testService == null) throw new ArgumentNullException("testService"); if (resourceService == null) throw new ArgumentNullException("resourceService"); this.testService = testService; this.resourceService = resourceService; SD.ProjectService.AllProjects.CollectionChanged += OnProjectsCollectionChanged; SD.ParserService.LoadSolutionProjectsThread.Finished += SD_ParserService_LoadSolutionProjectsThread_Finished; foreach (var project in SD.ProjectService.AllProjects) { AddProject(project); } SD_ParserService_LoadSolutionProjectsThread_Finished(null, null); } public override string DisplayName { get { return resourceService.GetString("ICSharpCode.UnitTesting.AllTestsTreeNode.Text"); } } public override event EventHandler DisplayNameChanged { add { resourceService.LanguageChanged += value; } remove { resourceService.LanguageChanged -= value; } } public override ITestProject ParentProject { get { return null; } } public ITestProject GetTestProject(IProject project) { for (int i = 0; i < changeListeners.Count; i++) { if (changeListeners[i].project == project) { return changeListeners[i].testProject; } } return null; } public IEnumerable GetTestsForEntity(IEntity entity) { if (entity == null) return Enumerable.Empty(); ITestProject testProject = GetTestProject(entity.ParentAssembly.GetProject()); if (testProject != null) return testProject.GetTestsForEntity(entity); else return Enumerable.Empty(); } public override IEnumerable GetUnitTestNames() { foreach (var project in changeListeners.Select(l => l.testProject)) { foreach (var name in project.GetUnitTestNames()) { yield return name; } } } /// /// Creates a TestProject for an IProject. /// This class takes care of changes in the test framework and will recreate the testProject /// if the test framework changes. /// class ProjectChangeListener { readonly TestSolution testSolution; ITestFramework oldTestFramework; internal readonly IProject project; internal ITestProject testProject; public ProjectChangeListener(TestSolution testSolution, IProject project) { this.testSolution = testSolution; this.project = project; } public void Start() { project.ParseInformationUpdated += project_ParseInformationUpdated; CheckTestFramework(); } public void Stop() { project.ParseInformationUpdated -= project_ParseInformationUpdated; // Remove old testProject if (testProject != null) { testSolution.NestedTestCollection.Remove(testProject); testProject = null; } } void project_ParseInformationUpdated(object sender, ParseInformationEventArgs e) { if (testProject != null) { testProject.NotifyParseInformationChanged(e.OldUnresolvedFile, e.NewUnresolvedFile); } } internal void CheckTestFramework() { ITestFramework newTestFramework = testSolution.testService.GetTestFrameworkForProject(project); if (newTestFramework == oldTestFramework) return; // test framework is unchanged // Remove old testProject if (testProject != null) { testSolution.NestedTestCollection.Remove(testProject); testProject = null; } // Create new testProject if (newTestFramework != null) { testProject = newTestFramework.CreateTestProject(testSolution, project); if (testProject == null) throw new InvalidOperationException("CreateTestProject() returned null"); testSolution.NestedTestCollection.Add(testProject); } oldTestFramework = newTestFramework; } } void OnProjectsCollectionChanged(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems) { for (int i = 0; i < changeListeners.Count; i++) { if (removedItems.Contains(changeListeners[i].project)) { changeListeners[i].Stop(); changeListeners.RemoveAt(i--); } } foreach (var project in addedItems) { AddProject(project); } } void AddProject(IProject project) { ProjectChangeListener listener = new ProjectChangeListener(this, project); changeListeners.Add(listener); listener.Start(); } void SD_ParserService_LoadSolutionProjectsThread_Finished(object sender, EventArgs e) { for (int i = 0; i < changeListeners.Count; i++) { changeListeners[i].CheckTestFramework(); } } } }