Example #1
0
        async Task <RazorCSharpParsedDocument> Parse(string text, bool isPreprocessed)
        {
            var project = Services.ProjectService.CreateDotNetProject("C#", "AspNetApp");

            project.FileName = UnitTests.TestBase.GetTempFile(".csproj");
            string      file        = UnitTests.TestBase.GetTempFile(".cshtml");
            ProjectFile projectFile = project.AddFile(file);

            if (isPreprocessed)
            {
                projectFile.Generator = "RazorTemplatePreprocessor";
            }

            var sev = new TestViewContent();

            sev.Project     = project;
            sev.ContentName = file;
            sev.Text        = text;

            var tww = new TestWorkbenchWindow();

            tww.ViewContent = sev;

            var doc = new TestDocument(tww);

            doc.Editor.FileName = sev.ContentName;
            doc.UpdateProject(project);

            solution = new MonoDevelop.Projects.Solution();
            solution.DefaultSolutionFolder.AddItem(project);
            solution.AddConfiguration("", true);
            await TypeSystemServiceTestExtensions.LoadSolution(solution);

            var parser = new RazorTestingParser {
                Doc = doc
            };
            var options = new ParseOptions {
                Project  = project,
                FileName = file,
                Content  = new StringTextSource(text)
            };

            return((RazorCSharpParsedDocument)parser.Parse(options, default(CancellationToken)).Result);
        }
        public async Task CSharpFile_BuildActionNone_FileNotUsed()
        {
            FilePath solFile = Util.GetSampleProject("build-action-none", "build-action-none.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var projects = ws.CurrentSolution.Projects.ToArray();

                        var project = projects.Single();

                        // Check that build action none .cs file is not used by the type system.
                        Assert.IsFalse(project.Documents.Any(d => d.Name == "DoNotCompile.cs"));
                        Assert.IsTrue(project.Documents.Any(d => d.Name == "Program.cs"));
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task MultiTargetFramework_ProjectReferences()
        {
            FilePath solFile = Util.GetSampleProject("multi-target-project-ref", "multi-target.sln");

            CreateNuGetConfigFile(solFile.ParentDirectory);
            Util.RunMSBuild($"/t:Restore /p:RestoreDisableParallel=true \"{solFile}\"");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var projectIds = ws.CurrentSolution.ProjectIds.ToArray();
                        var projects   = ws.CurrentSolution.Projects.ToArray();

                        var netframeworkProject    = projects.FirstOrDefault(p => p.Name == "multi-target (net471)");
                        var netstandardProject     = projects.FirstOrDefault(p => p.Name == "multi-target (netstandard1.0)");
                        var netframeworkProjectRef = projects.FirstOrDefault(p => p.Name == "multi-target-ref (net472)");
                        var netstandardProjectRef  = projects.FirstOrDefault(p => p.Name == "multi-target-ref (netstandard1.4)");

                        // Should be four projects - one for each target framework.
                        Assert.AreEqual(4, projectIds.Length);
                        Assert.AreEqual(4, projects.Length);

                        Assert.IsNotNull(netframeworkProject);
                        Assert.IsNotNull(netstandardProject);
                        Assert.IsNotNull(netframeworkProjectRef);
                        Assert.IsNotNull(netstandardProjectRef);

                        // Check project references.
                        var projectReferences = netstandardProjectRef.ProjectReferences.ToArray();

                        Assert.AreEqual(1, projectReferences.Length);
                        Assert.AreEqual(netstandardProject.Id, projectReferences [0].ProjectId);

                        projectReferences = netframeworkProjectRef.ProjectReferences.ToArray();

                        Assert.AreEqual(1, projectReferences.Length);
                        Assert.AreEqual(netframeworkProject.Id, projectReferences [0].ProjectId);
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
Example #4
0
        public async Task ReferenceCacheWorks()
        {
            string solFile = Util.GetSampleProject("console-project", "ConsoleProject.sln");

            using (var sol = (MonoDevelop.Projects.Solution) await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var manager = ws.MetadataReferenceManager;
                        var cache   = new MonoDevelopMetadataReferenceManager.MetadataReferenceCache();

                        // Create one with default assembly properties
                        var asm  = typeof(MonoDevelopMetadataReferenceManagerMetadataReferenceCacheTests).Assembly.Location;
                        var item = cache.GetOrCreate(manager, asm, MetadataReferenceProperties.Assembly);
                        Assert.IsNotNull(item);

                        var item2 = cache.GetOrCreate(manager, asm, MetadataReferenceProperties.Assembly);
                        Assert.AreSame(item, item2, "Item that is in cache should be returned");

                        // Create one with custom properties
                        var item3 = cache.GetOrCreate(manager, asm, MetadataReferenceProperties.Assembly.WithAliases(new [] { "a" }));
                        Assert.IsNotNull(item3);

                        var item4 = cache.GetOrCreate(manager, asm, MetadataReferenceProperties.Assembly.WithAliases(new [] { "a" }));
                        Assert.AreSame(item3, item4, "Item that is in cache should be returned");

                        // Clear the cache, new items should be returned from now on.
                        cache.ClearCache();

                        var item5 = cache.GetOrCreate(manager, asm, MetadataReferenceProperties.Assembly);
                        Assert.IsNotNull(item5);

                        Assert.AreNotSame(item, item5, "Cache was cleared, so new item should be returned");

                        var item6 = cache.GetOrCreate(manager, asm, MetadataReferenceProperties.Assembly.WithAliases(new [] { "a" }));
                        Assert.AreNotSame(item3, item6, "Cache was cleared, so new item should be returned");

                        cache.ClearCache();
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task SymlinkedFilesHaveProperdocumentRegistration()
        {
            if (Platform.IsWindows)
            {
                Assert.Ignore("Symlinks not supported on Windows");
            }

            FilePath solFile = Util.GetSampleProjectPath("symlinked-source-file", "test-symlinked-file", "test-symlinked-file.sln");

            var solutionDirectory = Path.GetDirectoryName(solFile);
            var dataFile          = Path.Combine(solutionDirectory, "SymlinkedFileData.txt");
            var data              = File.ReadAllLines(dataFile);
            var symlinkFileName   = Path.Combine(solutionDirectory, data [0]);
            var symlinkFileSource = Path.GetFullPath(Path.Combine(solutionDirectory, data [1]));

            File.Delete(symlinkFileName);
            Process.Start(new ProcessStartInfo("ln", $"-s '{symlinkFileSource}' '{symlinkFileName}'")
            {
                UseShellExecute = false,
            }).WaitForExit();

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var project = sol.GetAllProjects().Single();

                        foreach (var file in project.Files)
                        {
                            Assert.IsNotNull(IdeApp.TypeSystemService.GetDocumentId(project, file.FilePath.ResolveLinks()));
                            if (file.FilePath.FileName.EndsWith("SymlinkedFile.cs", StringComparison.Ordinal))
                            {
                                Assert.IsNull(IdeServices.TypeSystemService.GetDocumentId(project, file.FilePath));
                            }
                        }
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task EditorConfigFile_ModifiedExternally()
        {
            FilePath solFile = Util.GetSampleProject("additional-files", "additional-files.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var project = sol.GetAllProjects().Single();

                        FilePath editorConfigFileName = solFile.ParentDirectory.Combine(".editorconfig");
                        var      projectInfo          = ws.CurrentSolution.Projects.Single();
                        var      editorConfigDoc      = projectInfo.AnalyzerConfigDocuments.Single(d => d.FilePath == editorConfigFileName);

                        bool analyzerConfigDocumentChanged = false;
                        ws.WorkspaceChanged += (sender, e) => {
                            if (e.DocumentId == editorConfigDoc.Id &&
                                e.Kind == Microsoft.CodeAnalysis.WorkspaceChangeKind.AnalyzerConfigDocumentChanged)
                            {
                                analyzerConfigDocumentChanged = true;
                            }
                        };

                        // Add error style to .editorconfig
                        string contents =
                            "root = true\r\n" +
                            "\r\n" +
                            "[*.cs]\r\n" +
                            "csharp_style_var_for_built_in_types = true:error\r\n";
                        File.WriteAllText(editorConfigFileName, contents);
                        FileService.NotifyFileChanged(editorConfigFileName);

                        Func <bool> action = () => analyzerConfigDocumentChanged;
                        await AssertIsTrueWithTimeout(action, "Timed out waiting for analyzer config file changed event", 10000);
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task MultiTargetFramework_RemoveProject()
        {
            FilePath solFile = Util.GetSampleProject("multi-target-netframework", "multi-target.sln");

            CreateNuGetConfigFile(solFile.ParentDirectory);
            Util.RunMSBuild($"/t:Restore /p:RestoreDisableParallel=true \"{solFile}\"");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var project = sol.GetAllProjects().Single();

                        var projectIds = ws.CurrentSolution.ProjectIds.ToArray();
                        var projects   = ws.CurrentSolution.Projects.ToArray();

                        var netframeworkProject = projects.FirstOrDefault(p => p.Name == "multi-target (net472)");
                        var netstandardProject  = projects.FirstOrDefault(p => p.Name == "multi-target (netstandard1.0)");

                        // Should be two projects - one for each target framework.
                        Assert.AreEqual(2, projectIds.Length);
                        Assert.AreEqual(2, projects.Length);

                        Assert.IsNotNull(netframeworkProject);
                        Assert.IsNotNull(netstandardProject);

                        sol.RootFolder.Items.Remove(project);
                        await sol.SaveAsync(Util.GetMonitor());

                        projectIds = ws.CurrentSolution.ProjectIds.ToArray();
                        projects   = ws.CurrentSolution.Projects.ToArray();

                        Assert.AreEqual(0, projectIds.Length);
                        Assert.AreEqual(0, projects.Length);
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task AdditionalFiles_EditorConfigFiles()
        {
            FilePath solFile = Util.GetSampleProject("additional-files", "additional-files.sln");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var project = sol.GetAllProjects().Single();

                        var projectInfo      = ws.CurrentSolution.Projects.Single();
                        var additionalDocs   = projectInfo.AdditionalDocuments.ToArray();
                        var editorConfigDocs = projectInfo.AnalyzerConfigDocuments.ToArray();

                        FilePath expectedAdditionalFileName   = project.BaseDirectory.Combine("additional-file.txt");
                        FilePath expectedEditorConfigFileName = solFile.ParentDirectory.Combine(".editorconfig");

                        Assert.IsTrue(additionalDocs.Any(d => d.FilePath == expectedAdditionalFileName));
                        Assert.IsTrue(editorConfigDocs.Any(d => d.FilePath == expectedEditorConfigFileName));
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task ProjectReference()
        {
            FilePath solFile = Util.GetSampleProject("netstandard-project", "NetStandardTest.sln");

            CreateNuGetConfigFile(solFile.ParentDirectory);
            Util.RunMSBuild($"/t:Restore /p:RestoreDisableParallel=true \"{solFile}\"");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var projects = ws.CurrentSolution.Projects.ToArray();

                        var netframeworkProject = projects.FirstOrDefault(p => p.Name == "NetStandardTest");
                        var netstandardProject  = projects.FirstOrDefault(p => p.Name == "Lib");
                        var projectReferences   = netframeworkProject.ProjectReferences.ToArray();

                        Assert.AreEqual(1, projectReferences.Length);
                        Assert.AreEqual(netstandardProject.Id, projectReferences [0].ProjectId);
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
Example #10
0
        public async Task MetadataReferencesToFrameworkAssembliesAreProperlyFound()
        {
            if (!IdeApp.IsInitialized)
            {
                IdeApp.Initialize(new ProgressMonitor());
            }

            FilePath projFile = Util.GetSampleProject("workspace-metadata-references", "workspace-metadata-references.sln");

            using (var sol = (MonoDevelop.Projects.Solution) await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), projFile)) {
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    DotNetProject mainProject = null, libraryProject = null, libraryProject461 = null;
                    foreach (var project in sol.GetAllProjects())
                    {
                        if (project.Name == "workspace-metadata-references")
                        {
                            mainProject = (DotNetProject)project;
                        }
                        else if (project.Name == "library-project")
                        {
                            libraryProject = (DotNetProject)project;
                        }
                        else if (project.Name == "library-project-net461")
                        {
                            libraryProject461 = (DotNetProject)project;
                        }
                    }

                    Assert.IsNotNull(mainProject);
                    Assert.IsNotNull(libraryProject);

                    // Also, add test for net461 to net47.
                    await AddAssemblyReference(ws, libraryProject, mainProject, "System.Messaging");
                    await AddAssemblyReference(ws, libraryProject461, mainProject, "System.ServiceModel");
                }
            }
        }
Example #11
0
        static async Task <EditorInfo> CreateEditor(string text, bool isInCSharpContext)
        {
            string parsedText, editorText;
            int    cursorPosition = text.IndexOf('$');
            int    endPos         = text.IndexOf('$', cursorPosition + 1);

            if (endPos == -1)
            {
                parsedText = editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1);
            }
            else
            {
                parsedText     = text.Substring(0, cursorPosition) + new string (' ', endPos - cursorPosition) + text.Substring(endPos + 1);
                editorText     = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring(endPos + 1);
                cursorPosition = endPos - 1;
            }

            var project = Services.ProjectService.CreateProject("C#", "AspNetApp");

            project.FileName = UnitTests.TestBase.GetTempFile(".csproj");
            string file = UnitTests.TestBase.GetTempFile(extension);

            project.AddFile(file);

            var sev = new TestViewContent();

            sev.Project        = project;
            sev.ContentName    = file;
            sev.Text           = editorText;
            sev.CursorPosition = cursorPosition;

            var tww = new TestWorkbenchWindow();

            tww.ViewContent = sev;

            var doc = new TestDocument(tww);

            doc.Editor.FileName = sev.ContentName;
            doc.UpdateProject(project);

            solution = new MonoDevelop.Projects.Solution();
            solution.DefaultSolutionFolder.AddItem(project);
            solution.AddConfiguration("", true);
            await TypeSystemServiceTestExtensions.LoadSolution(solution);

            var parser = new RazorTestingParser {
                Doc = doc
            };
            var options = new ParseOptions {
                Project  = project,
                FileName = sev.ContentName,
                Content  = new StringTextSource(parsedText)
            };
            var parsedDoc = await parser.Parse(options, default(CancellationToken)) as RazorCSharpParsedDocument;

            doc.HiddenParsedDocument = parsedDoc;

            var editorExtension = new RazorCSharpEditorExtension(doc, parsedDoc as RazorCSharpParsedDocument, isInCSharpContext);

            return(new EditorInfo {
                Extension = editorExtension,
                EditorText = editorText,
                View = sev
            });
        }
        public async Task MultiTargetFramework()
        {
            FilePath solFile = Util.GetSampleProject("multi-target-netframework", "multi-target.sln");

            CreateNuGetConfigFile(solFile.ParentDirectory);
            Util.RunMSBuild($"/t:Restore /p:RestoreDisableParallel=true \"{solFile}\"");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var project = sol.GetAllProjects().Single();

                        var projectIds = ws.CurrentSolution.ProjectIds.ToArray();
                        var projects   = ws.CurrentSolution.Projects.ToArray();

                        var netframeworkProject = projects.FirstOrDefault(p => p.Name == "multi-target (net472)");
                        var netstandardProject  = projects.FirstOrDefault(p => p.Name == "multi-target (netstandard1.0)");

                        // Should be two projects - one for each target framework.
                        Assert.AreEqual(2, projectIds.Length);
                        Assert.AreEqual(2, projects.Length);

                        Assert.IsNotNull(netframeworkProject);
                        Assert.IsNotNull(netstandardProject);

                        // Check references.
                        var mscorlibNetFramework = netframeworkProject.MetadataReferences
                                                   .OfType <Microsoft.CodeAnalysis.PortableExecutableReference> ()
                                                   .FirstOrDefault(r => Path.GetFileName(r.FilePath) == "mscorlib.dll");

                        var systemCollectionsNetFramework = netframeworkProject.MetadataReferences
                                                            .OfType <Microsoft.CodeAnalysis.PortableExecutableReference> ()
                                                            .FirstOrDefault(r => Path.GetFileName(r.FilePath) == "System.Collections.dll");

                        var mscorlibNetStandard = netstandardProject.MetadataReferences
                                                  .OfType <Microsoft.CodeAnalysis.PortableExecutableReference> ()
                                                  .FirstOrDefault(r => Path.GetFileName(r.FilePath) == "mscorlib.dll");

                        var systemCollectionsNetStandard = netstandardProject.MetadataReferences
                                                           .OfType <Microsoft.CodeAnalysis.PortableExecutableReference> ()
                                                           .FirstOrDefault(r => Path.GetFileName(r.FilePath) == "System.Collections.dll");

                        Assert.AreNotEqual(netframeworkProject.MetadataReferences.Count, netstandardProject.MetadataReferences.Count);

                        Assert.IsNotNull(mscorlibNetFramework);
                        Assert.IsNull(mscorlibNetStandard);

                        Assert.IsNull(systemCollectionsNetFramework);
                        Assert.IsNotNull(systemCollectionsNetStandard);

                        // Check source files are correct for each framework.
                        Assert.IsFalse(netframeworkProject.Documents.Any(d => d.Name == "MyClass-netstandard.cs"));
                        Assert.IsTrue(netframeworkProject.Documents.Any(d => d.Name == "MyClass-netframework.cs"));
                        Assert.IsTrue(netstandardProject.Documents.Any(d => d.Name == "MyClass-netstandard.cs"));
                        Assert.IsFalse(netstandardProject.Documents.Any(d => d.Name == "MyClass-netframework.cs"));

                        // Check compiler parameter information
                        Assert.That(netframeworkProject.ParseOptions.PreprocessorSymbolNames, Contains.Item("NET472"));
                        Assert.That(netstandardProject.ParseOptions.PreprocessorSymbolNames, Contains.Item("NETSTANDARD1_0"));

                        Assert.That(netframeworkProject.CompilationOptions.SpecificDiagnosticOptions.Keys, Contains.Item("NET12345"));
                        Assert.IsFalse(netframeworkProject.CompilationOptions.SpecificDiagnosticOptions.Keys.Contains("STA4433"));
                        Assert.That(netstandardProject.CompilationOptions.SpecificDiagnosticOptions.Keys, Contains.Item("STA4433"));
                        Assert.IsFalse(netstandardProject.CompilationOptions.SpecificDiagnosticOptions.Keys.Contains("NET12345"));

                        // Ensure that facade assemblies are not added to the .NET Standard project. This would happen
                        // if the .NET Framework was the first target framework listed in TargetFrameworks. The Project
                        // would see a .NET Standard assembly was referenced and add the facade assemblies.
                        var facadeFound = netstandardProject.MetadataReferences
                                          .OfType <Microsoft.CodeAnalysis.PortableExecutableReference> ()
                                          .Where(r => r.FilePath.IndexOf("Facades", StringComparison.OrdinalIgnoreCase) >= 0)
                                          .Select(r => r.FilePath)
                                          .FirstOrDefault();

                        Assert.IsNull(facadeFound);
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task SingleTargetFramework_ReloadProjectAfterChangingToMultiTargetFramework_TypeSystemRespondsToProjectModifiedEvents()
        {
            FilePath solFile = Util.GetSampleProject("multi-target-reload", "multi-target-reload.sln");

            CreateNuGetConfigFile(solFile.ParentDirectory);
            Util.RunMSBuild($"/t:Restore /p:RestoreDisableParallel=true \"{solFile}\"");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var project = sol.GetAllProjects().Single();

                        var projectIds = ws.CurrentSolution.ProjectIds.ToArray();
                        var projects   = ws.CurrentSolution.Projects.ToArray();

                        // Should be one Roslyn project.
                        Assert.AreEqual(1, projectIds.Length);
                        Assert.AreEqual(1, projects.Length);

                        var updatedProjectFileName = project.FileName.ChangeName("multi-target-reload");

                        string xml = File.ReadAllText(updatedProjectFileName);
                        File.WriteAllText(project.FileName, xml);

                        var reloadedProject = (DotNetProject)await sol.RootFolder.ReloadItem(Util.GetMonitor(), project);

                        // Try a few times since the type system needs time to reload
                        const int timeout  = 10000;               // ms
                        int       howLong  = 0;
                        const int interval = 200;                 // ms


                        while (true)
                        {
                            var newProjectIds = ws.CurrentSolution.ProjectIds.ToArray();
                            projects = ws.CurrentSolution.Projects.ToArray();

                            var netstandardProject  = projects.FirstOrDefault(p => p.Name == "netstandard (netstandard2.0)");
                            var netframeworkProject = projects.FirstOrDefault(p => p.Name == "netstandard (net462)");
                            if (netframeworkProject != null && netstandardProject != null)
                            {
                                Assert.AreEqual(2, newProjectIds.Length);
                                Assert.AreEqual(2, projects.Length);
                                break;
                            }

                            if (howLong >= timeout)
                            {
                                Assert.Fail("Timed out waiting for type system information to be updated.");
                            }

                            await Task.Delay(interval);

                            howLong += interval;
                        }

                        // Add a new file.
                        var projectFileName = reloadedProject.BaseDirectory.Combine("Test.cs");
                        File.WriteAllText(projectFileName, "class Test { }");

                        var projectFile = new ProjectFile(projectFileName, BuildAction.Compile);
                        reloadedProject.Files.Add(projectFile);

                        howLong = 0;

                        while (true)
                        {
                            projects = ws.CurrentSolution.Projects.ToArray();

                            var netstandardProject  = projects.FirstOrDefault(p => p.Name == "netstandard (netstandard2.0)");
                            var netframeworkProject = projects.FirstOrDefault(p => p.Name == "netstandard (net462)");

                            if (netstandardProject.Documents.Any(d => d.Name == "Test.cs") &&
                                netframeworkProject.Documents.Any(d => d.Name == "Test.cs"))
                            {
                                // OK - document registered with type system service.
                                return;
                            }

                            if (howLong >= timeout)
                            {
                                Assert.Fail("Timed out waiting for type system information to be updated after adding file.");
                            }

                            await Task.Delay(interval);

                            howLong += interval;
                        }
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task MultiTargetFramework_ReloadProject_TargetFrameworksChanged()
        {
            FilePath solFile = Util.GetSampleProject("multi-target", "multi-target.sln");

            CreateNuGetConfigFile(solFile.ParentDirectory);
            Util.RunMSBuild($"/t:Restore /p:RestoreDisableParallel=true \"{solFile}\"");

            using (var sol = (Solution)await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                    try {
                        var project = sol.GetAllProjects().Single();

                        var projectIds = ws.CurrentSolution.ProjectIds.ToArray();
                        var projects   = ws.CurrentSolution.Projects.ToArray();

                        var netcoreProject     = projects.FirstOrDefault(p => p.Name == "multi-target (netcoreapp1.1)");
                        var netstandardProject = projects.FirstOrDefault(p => p.Name == "multi-target (netstandard1.0)");

                        // Should be two projects - one for each target framework.
                        Assert.AreEqual(2, projectIds.Length);
                        Assert.AreEqual(2, projects.Length);

                        Assert.IsNotNull(netcoreProject);
                        Assert.IsNotNull(netstandardProject);

                        var updatedProjectFileName = project.FileName.ChangeName("multi-target-reload");

                        string xml = File.ReadAllText(updatedProjectFileName);
                        File.WriteAllText(project.FileName, xml);

                        await sol.RootFolder.ReloadItem(Util.GetMonitor(), project);

                        // Try a few times since the type system needs time to reload
                        const int timeout  = 10000;               // ms
                        int       howLong  = 0;
                        const int interval = 200;                 // ms

                        while (true)
                        {
                            var newProjectIds = ws.CurrentSolution.ProjectIds.ToArray();
                            projects = ws.CurrentSolution.Projects.ToArray();

                            netcoreProject     = projects.FirstOrDefault(p => p.Name == "multi-target (netcoreapp1.2)");
                            netstandardProject = projects.FirstOrDefault(p => p.Name == "multi-target (netstandard1.3)");
                            if (netcoreProject != null && netstandardProject != null)
                            {
                                Assert.AreEqual(2, newProjectIds.Length);
                                Assert.AreEqual(2, projects.Length);
                                return;
                            }

                            if (howLong >= timeout)
                            {
                                Assert.Fail("Timed out waiting for type system information to be updated.");
                            }

                            await Task.Delay(interval);

                            howLong += interval;
                        }
                    } finally {
                        TypeSystemServiceTestExtensions.UnloadSolution(sol);
                    }
                }
        }
        public async Task ReferenceCacheSnapshotUpdates()
        {
            string solFile = Util.GetSampleProject("console-project", "ConsoleProject.sln");

            var tempPath = Path.GetFullPath(Path.GetTempFileName());
            var oldAsm   = typeof(MonoDevelopMetadataReferenceManagerTests).Assembly.Location;

            File.Copy(oldAsm, tempPath, true);

            try {
                using (var sol = (MonoDevelop.Projects.Solution) await Services.ProjectService.ReadWorkspaceItem(Util.GetMonitor(), solFile))
                    using (var ws = await TypeSystemServiceTestExtensions.LoadSolution(sol)) {
                        await FileWatcherService.Add(sol);

                        var manager = ws.MetadataReferenceManager;
                        var item    = manager.GetOrCreateMetadataReference(tempPath, MetadataReferenceProperties.Assembly);
                        Assert.IsNotNull(item);

                        await FileWatcherService.Update();

                        var initialId = item.CurrentSnapshot.GetMetadataId();

                        var taskForNewAsm = WaitForSnapshotChange(item);

                        // Replace the assembly with another one.
                        var newAsm = typeof(MonoDevelopMetadataReference).Assembly.Location;
                        File.Copy(newAsm, tempPath, true);

                        var argsForNewAsm = await taskForNewAsm;

                        Assert.AreSame(item.CurrentSnapshot, argsForNewAsm.OldSnapshot);

                        Assert.AreNotSame(argsForNewAsm.OldSnapshot, argsForNewAsm.NewSnapshot.Value);
                        // item.CurrentSnapshot is now updated
                        Assert.AreNotEqual(initialId, item.CurrentSnapshot.GetMetadataId());

                        var taskForOldAsm = WaitForSnapshotChange(item);
                        File.Copy(newAsm, tempPath, true);

                        var argsForOldAsm = await taskForOldAsm;

                        Assert.AreSame(item.CurrentSnapshot, argsForOldAsm.OldSnapshot);

                        Assert.AreNotSame(argsForNewAsm.OldSnapshot, argsForNewAsm.NewSnapshot.Value);
                        // Even though the old assembly was put back, it has a new id this time.
                        Assert.AreNotEqual(initialId, item.CurrentSnapshot.GetMetadataId());
                    }

                await FileWatcherService.Update();

                // At this point, the metadata reference should be disposed.
                // Check to see if file updates will trigger a file service noification
                var tcsShouldTimeout = new TaskCompletionSource <bool> ();
                var ctsFail          = new CancellationTokenSource();
                ctsFail.Token.Register(() => tcsShouldTimeout.TrySetResult(true));
                Core.FileService.FileChanged += (sender, args) => {
                    foreach (var file in args)
                    {
                        if (file.FileName == tempPath)
                        {
                            tcsShouldTimeout.TrySetResult(false);
                        }
                    }
                };

                ctsFail.CancelAfter(1000 * 5);
                File.WriteAllText(tempPath, "");
                Assert.AreEqual(true, await tcsShouldTimeout.Task);
            } finally {
                File.Delete(tempPath);
            }
        }