internal static TestHostDocument CreateDocument(
            XElement documentElement,
            ExportProvider exportProvider,
            HostLanguageServices languageServiceProvider,
            ImmutableArray <string> roles)
        {
            string markupCode = documentElement.NormalizedValue();

            var folders        = GetFolders(documentElement);
            var optionsElement = documentElement.Element(ParseOptionsElementName);

            var codeKind = SourceCodeKind.Regular;

            if (optionsElement != null)
            {
                var attr = optionsElement.Attribute(KindAttributeName);
                codeKind = attr == null
                    ? SourceCodeKind.Regular
                    : (SourceCodeKind)Enum.Parse(typeof(SourceCodeKind), attr.Value);
            }

            MarkupTestFile.GetPositionAndSpans(markupCode,
                                               out var code, out var cursorPosition, out IDictionary <string, ImmutableArray <TextSpan> > spans);

            var documentServiceProvider = GetDocumentServiceProvider(documentElement);

            return(new TestHostDocument(
                       exportProvider, languageServiceProvider, code, filePath: string.Empty, cursorPosition, spans, codeKind, folders, isLinkFile: false, documentServiceProvider, roles: roles));
        }
        private static void VerifyResolution(string markup, string[] fxCopFullyQualifiedNames, SuppressMessageAttributeState.TargetScope scope, string language, string rootNamespace)
        {
            // Parse out the span containing the declaration of the expected symbol
            MarkupTestFile.GetPositionAndSpans(markup,
                                               out var source, out var pos, out IDictionary <string, ImmutableArray <TextSpan> > spans);

            Assert.True(pos != null || spans.Count > 0, "Must specify a position or spans marking expected symbols for resolution");

            // Get the expected symbol from the given position
            var syntaxTree      = CreateSyntaxTree(source, language);
            var compilation     = CreateCompilation(syntaxTree, language, rootNamespace);
            var model           = compilation.GetSemanticModel(syntaxTree);
            var expectedSymbols = new List <ISymbol>();

            bool shouldResolveSingleSymbol = pos != null;

            if (shouldResolveSingleSymbol)
            {
                expectedSymbols.Add(GetSymbolAtPosition(model, pos.Value));
            }
            else
            {
                foreach (var span in spans.Values.First())
                {
                    expectedSymbols.Add(GetSymbolAtPosition(model, span.Start));
                }
            }

            // Resolve the symbol based on each given FxCop fully-qualified name
            foreach (var fxCopName in fxCopFullyQualifiedNames)
            {
                var symbols = SuppressMessageAttributeState.ResolveTargetSymbols(compilation, fxCopName, scope);

                if (shouldResolveSingleSymbol)
                {
                    var expectedSymbol = expectedSymbols.Single();

                    if (symbols.Count() > 1)
                    {
                        Assert.True(false,
                                    string.Format("Expected to resolve FxCop fully-qualified name '{0}' to '{1}': got multiple symbols:\r\n{2}",
                                                  fxCopName, expectedSymbol, string.Join("\r\n", symbols)));
                    }

                    var symbol = symbols.SingleOrDefault();
                    Assert.True(expectedSymbol == symbol,
                                string.Format("Failed to resolve FxCop fully-qualified name '{0}' to symbol '{1}': got '{2}'",
                                              fxCopName, expectedSymbol, symbol));
                }
                else
                {
                    foreach (var symbol in symbols)
                    {
                        Assert.True(expectedSymbols.Contains(symbol),
                                    string.Format("Failed to resolve FxCop fully-qualified name '{0}' to symbols:\r\n{1}\r\nResolved to unexpected symbol '{2}'",
                                                  fxCopName, string.Join("\r\n", expectedSymbols), symbol));
                    }
                }
            }
        }
Example #3
0
        protected void TestTrivia(string expectedRegionName, string code, SyntaxKind expectedKind, bool autoCollapse)
        {
            int caretPosition;
            IList <TextSpan> spans;

            MarkupTestFile.GetPositionAndSpans(code, out code, out caretPosition, out spans);

            var tree      = ParseCode(code);
            var trivia    = tree.GetRoot().FindTrivia(caretPosition);
            var directive = trivia.GetStructure() as TSyntaxNode;

            Assert.NotNull(directive);
            Assert.Equal(expectedKind, directive.Kind());

            var actualRegions = GetRegions(directive).ToArray();

            if (spans.Count == 0)
            {
                Assert.Equal(0, actualRegions.Length);
                return;
            }

            Assert.Equal(1, actualRegions.Length);
            var expectedRegion = new OutliningSpan(
                spans[0],
                expectedRegionName,
                autoCollapse);

            AssertRegion(expectedRegion, actualRegions[0]);
        }
Example #4
0
        protected async Task SetUpEditorAsync(string markupCode, CancellationToken cancellationToken)
        {
            MarkupTestFile.GetPositionAndSpans(markupCode, out var code, out int?caretPosition, out var spans);

            Assert.True(caretPosition.HasValue || spans.ContainsKey("selection"), "Must specify either a caret position ($$) or at least one selection span ({|selection:|})");

            await TestServices.Editor.DismissCompletionSessionsAsync(cancellationToken);

            await TestServices.Editor.DismissLightBulbSessionAsync(cancellationToken);

            var originalValue = await TestServices.Workspace.IsPrettyListingOnAsync(LanguageName, cancellationToken);

            await TestServices.Workspace.SetPrettyListingAsync(LanguageName, false, cancellationToken);

            try
            {
                await TestServices.Editor.SetTextAsync(code, cancellationToken);

                if (caretPosition.HasValue)
                {
                    await TestServices.Editor.MoveCaretAsync(caretPosition.Value, cancellationToken);
                }
                else
                {
                    await TestServices.Editor.SetMultiSelectionAsync(spans["selection"], cancellationToken);
                }

                await TestServices.Editor.ActivateAsync(cancellationToken);
            }
            finally
            {
                await TestServices.Workspace.SetPrettyListingAsync(LanguageName, originalValue, cancellationToken);
            }
        }
        protected async Task TestBraceHighlightingAsync(
            string markup,
            ParseOptions options        = null,
            bool swapAnglesWithBrackets = false
            )
        {
            MarkupTestFile.GetPositionAndSpans(
                markup,
                out var text,
                out int cursorPosition,
                out var expectedSpans
                );

            // needed because markup test file can't support [|[|] to indicate selecting
            // just an open bracket.
            if (swapAnglesWithBrackets)
            {
                text = text.Replace("<", "[").Replace(">", "]");
            }

            using (var workspace = CreateWorkspace(text, options))
            {
                WpfTestRunner.RequireWpfFact(
                    $"{nameof(AbstractBraceHighlightingTests)}.{nameof(TestBraceHighlightingAsync)} creates asynchronous taggers"
                    );

                var provider = new BraceHighlightingViewTaggerProvider(
                    workspace.GetService <IThreadingContext>(),
                    GetBraceMatchingService(workspace),
                    workspace.GetService <IForegroundNotificationService>(),
                    AsynchronousOperationListenerProvider.NullProvider
                    );

                var testDocument = workspace.Documents.First();
                var buffer       = testDocument.GetTextBuffer();
                var document     = buffer.CurrentSnapshot
                                   .GetRelatedDocumentsWithChanges()
                                   .FirstOrDefault();
                var context = new TaggerContext <BraceHighlightTag>(
                    document,
                    buffer.CurrentSnapshot,
                    new SnapshotPoint(buffer.CurrentSnapshot, cursorPosition)
                    );
                await provider.GetTestAccessor().ProduceTagsAsync(context);

                var expectedHighlights = expectedSpans
                                         .Select(ts => ts.ToSpan())
                                         .OrderBy(s => s.Start)
                                         .ToList();
                var actualHighlights = context.tagSpans
                                       .Select(ts => ts.Span.Span)
                                       .OrderBy(s => s.Start)
                                       .ToList();

                Assert.Equal(expectedHighlights, actualHighlights);
            }
        }
        private static IList <TestHostProject> CreateSubmissions(
            TestWorkspace workspace,
            IEnumerable <XElement> submissionElements,
            ExportProvider exportProvider)
        {
            var submissions     = new List <TestHostProject>();
            var submissionIndex = 0;

            foreach (var submissionElement in submissionElements)
            {
                var submissionName = "Submission" + (submissionIndex++);

                var languageName = GetLanguage(workspace, submissionElement);

                // The document
                var    markupCode = submissionElement.NormalizedValue();
                string code;
                int?   cursorPosition;
                IDictionary <string, IList <TextSpan> > spans;
                MarkupTestFile.GetPositionAndSpans(markupCode, out code, out cursorPosition, out spans);

                var languageServices           = workspace.Services.GetLanguageServices(languageName);
                var contentTypeLanguageService = languageServices.GetService <IContentTypeLanguageService>();

                var contentType = contentTypeLanguageService.GetDefaultContentType();
                var textBuffer  = EditorFactory.CreateBuffer(contentType.TypeName, exportProvider, code);

                // The project

                var document = new TestHostDocument(exportProvider, languageServices, textBuffer, submissionName, cursorPosition, spans, SourceCodeKind.Interactive);

                var syntaxFactory      = languageServices.GetService <ISyntaxTreeFactoryService>();
                var compilationFactory = languageServices.GetService <ICompilationFactoryService>();
                var compilationOptions = compilationFactory.GetDefaultCompilationOptions().WithOutputKind(OutputKind.DynamicallyLinkedLibrary);

                var parseOptions = syntaxFactory.GetDefaultParseOptions().WithKind(SourceCodeKind.Interactive);

                var references = CreateCommonReferences(workspace, submissionElement);

                var project = new TestHostProject(
                    languageServices,
                    compilationOptions,
                    parseOptions,
                    submissionName,
                    references,
                    new List <TestHostDocument> {
                    document
                }, isSubmission: true);

                submissions.Add(project);
            }

            return(submissions);
        }
        private async Task TestSignatureHelpWorkerAsync(
            string markupWithPositionAndOptSpan,
            SourceCodeKind sourceCodeKind,
            bool experimental,
            IEnumerable <SignatureHelpTestItem> expectedOrderedItemsOrNull = null,
            bool usePreviousCharAsTrigger = false)
        {
            markupWithPositionAndOptSpan = markupWithPositionAndOptSpan.NormalizeLineEndings();

            string           code;
            int              cursorPosition;
            IList <TextSpan> textSpans;
            TextSpan?        textSpan = null;

            MarkupTestFile.GetPositionAndSpans(
                markupWithPositionAndOptSpan,
                out code,
                out cursorPosition,
                out textSpans);

            if (textSpans.Any())
            {
                textSpan = textSpans.First();
            }

            var parseOptions = CreateExperimentalParseOptions();

            // regular
            var document1 = await workspaceFixture.UpdateDocumentAsync(code, sourceCodeKind);

            if (experimental)
            {
                document1 = document1.Project.WithParseOptions(parseOptions).GetDocument(document1.Id);
            }

            await TestSignatureHelpWorkerSharedAsync(code, cursorPosition, sourceCodeKind, document1, textSpan, expectedOrderedItemsOrNull, usePreviousCharAsTrigger);

            // speculative semantic model
            if (await CanUseSpeculativeSemanticModelAsync(document1, cursorPosition))
            {
                var document2 = await workspaceFixture.UpdateDocumentAsync(code, sourceCodeKind, cleanBeforeUpdate : false);

                if (experimental)
                {
                    document2 = document2.Project.WithParseOptions(parseOptions).GetDocument(document2.Id);
                }

                await TestSignatureHelpWorkerSharedAsync(code, cursorPosition, sourceCodeKind, document2, textSpan, expectedOrderedItemsOrNull, usePreviousCharAsTrigger);
            }
        }
Example #8
0
        private static async Task TestAsync(string markup, string output)
        {
            MarkupTestFile.GetPositionAndSpans(markup, out var text, out var cursorPosition, out IDictionary <string, ImmutableArray <TextSpan> > placeholderDictionary);
            var stringSpan   = placeholderDictionary[""].First();
            var textChange   = new TextChange(new TextSpan(stringSpan.Start, 0), text.Substring(stringSpan.Start, stringSpan.Length));
            var placeholders = GetSnippetPlaceholders(text, placeholderDictionary);

            using var workspace = CreateWorkspaceFromCode(markup);
            var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id);

            var lspSnippetString = await RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(document, cursorPosition !.Value, placeholders, textChange, stringSpan.Start, CancellationToken.None).ConfigureAwait(false);

            AssertEx.EqualOrDiff(output, lspSnippetString);
        }
Example #9
0
            internal void AssertCodeIs(string expectedCode)
            {
                MarkupTestFile.GetPositionAndSpans(expectedCode, out var massaged, out int?caretPosition, out var spans);
                Assert.Equal(massaged, TextView.TextSnapshot.GetText());
                Assert.Equal(caretPosition !.Value, TextView.Caret.Position.BufferPosition.Position);

                var virtualSpaces = spans.SingleOrDefault(kvp => kvp.Key.StartsWith("VirtualSpaces#"));

                if (virtualSpaces.Key != null)
                {
                    var virtualOffset = int.Parse(virtualSpaces.Key.Substring("VirtualSpaces-".Length));
                    Assert.True(TextView.Caret.InVirtualSpace);
                    Assert.Equal(virtualOffset, TextView.Caret.Position.VirtualBufferPosition.VirtualSpaces);
                }
            }
        private static TestHostDocument CreateDocument(
            TestWorkspace workspace,
            XElement workspaceElement,
            XElement documentElement,
            string language,
            ExportProvider exportProvider,
            HostLanguageServices languageServiceProvider,
            Dictionary <string, ITextBuffer> filePathToTextBufferMap,
            ref int documentId)
        {
            string markupCode;
            string filePath;

            var  isLinkFileAttribute = documentElement.Attribute(IsLinkFileAttributeName);
            bool isLinkFile          = isLinkFileAttribute != null && ((bool?)isLinkFileAttribute).HasValue && ((bool?)isLinkFileAttribute).Value;

            if (isLinkFile)
            {
                // This is a linked file. Use the filePath and markup from the referenced document.

                var originalProjectName  = documentElement.Attribute(LinkAssemblyNameAttributeName);
                var originalDocumentPath = documentElement.Attribute(LinkFilePathAttributeName);

                if (originalProjectName == null || originalDocumentPath == null)
                {
                    throw new ArgumentException("Linked file specified without LinkAssemblyName or LinkFilePath.");
                }

                var originalProjectNameStr  = originalProjectName.Value;
                var originalDocumentPathStr = originalDocumentPath.Value;

                var originalProject = workspaceElement.Elements(ProjectElementName).First(p =>
                {
                    var assemblyName = p.Attribute(AssemblyNameAttributeName);
                    return(assemblyName != null && assemblyName.Value == originalProjectNameStr);
                });

                if (originalProject == null)
                {
                    throw new ArgumentException("Linked file's LinkAssemblyName '{0}' project not found.", originalProjectNameStr);
                }

                var originalDocument = originalProject.Elements(DocumentElementName).First(d =>
                {
                    var documentPath = d.Attribute(FilePathAttributeName);
                    return(documentPath != null && documentPath.Value == originalDocumentPathStr);
                });

                if (originalDocument == null)
                {
                    throw new ArgumentException("Linked file's LinkFilePath '{0}' file not found.", originalDocumentPathStr);
                }

                markupCode = originalDocument.NormalizedValue();
                filePath   = GetFilePath(workspace, originalDocument, ref documentId);
            }
            else
            {
                markupCode = documentElement.NormalizedValue();
                filePath   = GetFilePath(workspace, documentElement, ref documentId);
            }

            var folders        = GetFolders(documentElement);
            var optionsElement = documentElement.Element(ParseOptionsElementName);

            // TODO: Allow these to be specified.
            var codeKind = SourceCodeKind.Regular;

            if (optionsElement != null)
            {
                var attr = optionsElement.Attribute(KindAttributeName);
                codeKind = attr == null
                    ? SourceCodeKind.Regular
                    : (SourceCodeKind)Enum.Parse(typeof(SourceCodeKind), attr.Value);
            }

            var contentTypeLanguageService = languageServiceProvider.GetService <IContentTypeLanguageService>();
            var contentType = contentTypeLanguageService.GetDefaultContentType();

            string code;
            int?   cursorPosition;
            IDictionary <string, IList <TextSpan> > spans;

            MarkupTestFile.GetPositionAndSpans(markupCode, out code, out cursorPosition, out spans);

            // For linked files, use the same ITextBuffer for all linked documents
            ITextBuffer textBuffer;

            if (!filePathToTextBufferMap.TryGetValue(filePath, out textBuffer))
            {
                textBuffer = EditorFactory.CreateBuffer(contentType.TypeName, exportProvider, code);
                filePathToTextBufferMap.Add(filePath, textBuffer);
            }

            return(new TestHostDocument(exportProvider, languageServiceProvider, textBuffer, filePath, cursorPosition, spans, codeKind, folders, isLinkFile));
        }
Example #11
0
        private static void GetSpansAndCaretFromSurfaceBufferMarkup(
            string markup, IList <TestHostDocument> baseDocuments,
            out IList <object> projectionBufferSpans,
            out Dictionary <string, ImmutableArray <TextSpan> > mappedMarkupSpans, out int?mappedCaretLocation)
        {
            projectionBufferSpans = new List <object>();
            var projectionBufferSpanStartingPositions = new List <int>();

            mappedCaretLocation = null;

            MarkupTestFile.GetPositionAndSpans(markup,
                                               out var inertText, out int?markupCaretLocation, out var markupSpans);

            var namedSpans          = markupSpans.Where(kvp => kvp.Key != string.Empty);
            var sortedAndNamedSpans = namedSpans.OrderBy(kvp => kvp.Value.Single().Start)
                                      .ThenBy(kvp => markup.IndexOf("{|" + kvp.Key + ":", StringComparison.Ordinal));

            var currentPositionInInertText        = 0;
            var currentPositionInProjectionBuffer = 0;

            // If the markup points to k spans, these k spans divide the inert text into k + 1
            // possibly empty substrings. When handling each span, also handle the inert text that
            // immediately precedes it. At the end, handle the trailing inert text
            foreach (var spanNameToListMap in sortedAndNamedSpans)
            {
                var spanName     = spanNameToListMap.Key;
                var spanLocation = spanNameToListMap.Value.Single().Start;

                // Get any inert text between this and the previous span
                if (currentPositionInInertText < spanLocation)
                {
                    var textToAdd = inertText.Substring(currentPositionInInertText, spanLocation - currentPositionInInertText);
                    projectionBufferSpans.Add(textToAdd);
                    projectionBufferSpanStartingPositions.Add(currentPositionInProjectionBuffer);

                    // If the caret is in the markup and in this substring, calculate the final
                    // caret location
                    if (mappedCaretLocation == null &&
                        markupCaretLocation != null &&
                        currentPositionInInertText + textToAdd.Length >= markupCaretLocation)
                    {
                        var caretOffsetInCurrentText = markupCaretLocation.Value - currentPositionInInertText;
                        mappedCaretLocation = currentPositionInProjectionBuffer + caretOffsetInCurrentText;
                    }

                    currentPositionInInertText        += textToAdd.Length;
                    currentPositionInProjectionBuffer += textToAdd.Length;
                }

                // Find and insert the span from the corresponding document
                var documentWithSpan = baseDocuments.FirstOrDefault(d => d.AnnotatedSpans.ContainsKey(spanName));
                if (documentWithSpan == null)
                {
                    continue;
                }

                markupSpans.Remove(spanName);

                var matchingSpan = documentWithSpan.AnnotatedSpans[spanName].Single();
                var span         = new Span(matchingSpan.Start, matchingSpan.Length);
                var trackingSpan = documentWithSpan.GetTextBuffer().CurrentSnapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeExclusive);

                projectionBufferSpans.Add(trackingSpan);
                projectionBufferSpanStartingPositions.Add(currentPositionInProjectionBuffer);

                // If the caret is not in markup but is in this span, then calculate the final
                // caret location.  Note - if we find the caret marker in this document, then
                // we DO want to map it up, even if it's at the end of the span for this document.
                // This is not ambiguous for us, since we have explicit delimiters between the buffer
                // so it's clear which document the caret is in.
                if (mappedCaretLocation == null &&
                    markupCaretLocation == null &&
                    documentWithSpan.CursorPosition.HasValue &&
                    (matchingSpan.Contains(documentWithSpan.CursorPosition.Value) || matchingSpan.End == documentWithSpan.CursorPosition.Value))
                {
                    var caretOffsetInSpan = documentWithSpan.CursorPosition.Value - matchingSpan.Start;
                    mappedCaretLocation = currentPositionInProjectionBuffer + caretOffsetInSpan;
                }

                currentPositionInProjectionBuffer += matchingSpan.Length;
            }

            // Handle any inert text after the final projected span
            if (currentPositionInInertText < inertText.Length - 1)
            {
                projectionBufferSpans.Add(inertText.Substring(currentPositionInInertText));
                projectionBufferSpanStartingPositions.Add(currentPositionInProjectionBuffer);

                if (mappedCaretLocation == null && markupCaretLocation != null && markupCaretLocation >= currentPositionInInertText)
                {
                    var caretOffsetInCurrentText = markupCaretLocation.Value - currentPositionInInertText;
                    mappedCaretLocation = currentPositionInProjectionBuffer + caretOffsetInCurrentText;
                }
            }

            MapMarkupSpans(markupSpans, out mappedMarkupSpans, projectionBufferSpans, projectionBufferSpanStartingPositions);
        }
        private static TestHostDocument CreateDocument(
            TestWorkspace workspace,
            XElement workspaceElement,
            XElement documentElement,
            string language,
            ExportProvider exportProvider,
            HostLanguageServices languageServiceProvider,
            Dictionary <string, ITextBuffer> filePathToTextBufferMap,
            IDocumentServiceProvider documentServiceProvider,
            ref int documentId)
        {
            string markupCode;
            string filePath;

            var isLinkFileAttribute = documentElement.Attribute(IsLinkFileAttributeName);
            var isLinkFile          = isLinkFileAttribute != null && ((bool?)isLinkFileAttribute).HasValue && ((bool?)isLinkFileAttribute).Value;

            if (isLinkFile)
            {
                // This is a linked file. Use the filePath and markup from the referenced document.

                var originalAssemblyName = documentElement.Attribute(LinkAssemblyNameAttributeName)?.Value;
                var originalProjectName  = documentElement.Attribute(LinkProjectNameAttributeName)?.Value;

                if (originalAssemblyName == null && originalProjectName == null)
                {
                    throw new ArgumentException($"Linked files must specify either a {LinkAssemblyNameAttributeName} or {LinkProjectNameAttributeName}");
                }

                var originalProject = workspaceElement.Elements(ProjectElementName).FirstOrDefault(p =>
                {
                    if (originalAssemblyName != null)
                    {
                        return(p.Attribute(AssemblyNameAttributeName)?.Value == originalAssemblyName);
                    }
                    else
                    {
                        return(p.Attribute(ProjectNameAttribute)?.Value == originalProjectName);
                    }
                });

                if (originalProject == null)
                {
                    if (originalProjectName != null)
                    {
                        throw new ArgumentException($"Linked file's {LinkProjectNameAttributeName} '{originalProjectName}' project not found.");
                    }
                    else
                    {
                        throw new ArgumentException($"Linked file's {LinkAssemblyNameAttributeName} '{originalAssemblyName}' project not found.");
                    }
                }

                var originalDocumentPath = documentElement.Attribute(LinkFilePathAttributeName)?.Value;

                if (originalDocumentPath == null)
                {
                    throw new ArgumentException($"Linked files must specify a {LinkFilePathAttributeName}");
                }

                documentElement = originalProject.Elements(DocumentElementName).FirstOrDefault(d =>
                {
                    return(d.Attribute(FilePathAttributeName)?.Value == originalDocumentPath);
                });

                if (documentElement == null)
                {
                    throw new ArgumentException($"Linked file's LinkFilePath '{originalDocumentPath}' file not found.");
                }
            }

            markupCode = documentElement.NormalizedValue();
            filePath   = GetFilePath(workspace, documentElement, ref documentId);

            var folders        = GetFolders(documentElement);
            var optionsElement = documentElement.Element(ParseOptionsElementName);

            // TODO: Allow these to be specified.
            var codeKind = SourceCodeKind.Regular;

            if (optionsElement != null)
            {
                var attr = optionsElement.Attribute(KindAttributeName);
                codeKind = attr == null
                    ? SourceCodeKind.Regular
                    : (SourceCodeKind)Enum.Parse(typeof(SourceCodeKind), attr.Value);
            }

            var contentTypeLanguageService = languageServiceProvider.GetService <IContentTypeLanguageService>();
            var contentType = contentTypeLanguageService.GetDefaultContentType();

            MarkupTestFile.GetPositionAndSpans(markupCode,
                                               out var code, out var cursorPosition, out IDictionary <string, ImmutableArray <TextSpan> > spans);

            var testDocumentServiceProvider = GetDocumentServiceProvider(documentElement);

            if (documentServiceProvider == null)
            {
                documentServiceProvider = testDocumentServiceProvider;
            }
            else if (testDocumentServiceProvider != null)
            {
                AssertEx.Fail($"The document attributes on file {filePath} conflicted");
            }

            return(new TestHostDocument(
                       exportProvider, languageServiceProvider, code, filePath, cursorPosition, spans, codeKind, folders, isLinkFile, documentServiceProvider));
        }
        private static IList <TestHostProject> CreateSubmissions(
            TestWorkspace workspace,
            IEnumerable <XElement> submissionElements,
            ExportProvider exportProvider)
        {
            var submissions     = new List <TestHostProject>();
            var submissionIndex = 0;

            foreach (var submissionElement in submissionElements)
            {
                var submissionName = "Submission" + (submissionIndex++);

                var languageName = GetLanguage(workspace, submissionElement);

                // The document
                var markupCode = submissionElement.NormalizedValue();
                MarkupTestFile.GetPositionAndSpans(markupCode,
                                                   out var code, out var cursorPosition, out IDictionary <string, ImmutableArray <TextSpan> > spans);

                var languageServices = workspace.Services.GetLanguageServices(languageName);

                // The project

                var document  = new TestHostDocument(exportProvider, languageServices, code, submissionName, cursorPosition, spans, SourceCodeKind.Script);
                var documents = new List <TestHostDocument> {
                    document
                };

                if (languageName == NoCompilationConstants.LanguageName)
                {
                    submissions.Add(
                        new TestHostProject(
                            languageServices,
                            compilationOptions: null,
                            parseOptions: null,
                            assemblyName: submissionName,
                            projectName: submissionName,
                            references: null,
                            documents: documents,
                            isSubmission: true));
                    continue;
                }

                var syntaxFactory      = languageServices.GetService <ISyntaxTreeFactoryService>();
                var compilationFactory = languageServices.GetService <ICompilationFactoryService>();
                var compilationOptions = compilationFactory.GetDefaultCompilationOptions().WithOutputKind(OutputKind.DynamicallyLinkedLibrary);

                var parseOptions = syntaxFactory.GetDefaultParseOptions().WithKind(SourceCodeKind.Script);

                var references = CreateCommonReferences(workspace, submissionElement);

                var project = new TestHostProject(
                    languageServices,
                    compilationOptions,
                    parseOptions,
                    submissionName,
                    submissionName,
                    references,
                    documents,
                    isSubmission: true);

                submissions.Add(project);
            }

            return(submissions);
        }
        private static TestHostProject CreateProject(
            XElement workspaceElement,
            XElement projectElement,
            ExportProvider exportProvider,
            TestWorkspace workspace,
            IDocumentServiceProvider documentServiceProvider,
            ref int projectId,
            ref int documentId)
        {
            AssertNoChildText(projectElement);

            var language = GetLanguage(workspace, projectElement);

            var assemblyName = GetAssemblyName(workspace, projectElement, ref projectId);

            string filePath;

            var projectName = projectElement.Attribute(ProjectNameAttribute)?.Value ?? assemblyName;

            if (projectElement.Attribute(FilePathAttributeName) != null)
            {
                filePath = projectElement.Attribute(FilePathAttributeName).Value;
                if (string.Compare(filePath, NullFilePath, StringComparison.Ordinal) == 0)
                {
                    // allow explicit null file path
                    filePath = null;
                }
            }
            else
            {
                filePath = projectName +
                           (language == LanguageNames.CSharp ? ".csproj" :
                            language == LanguageNames.VisualBasic ? ".vbproj" : ("." + language));
            }

            var languageServices = workspace.Services.GetLanguageServices(language);

            var parseOptions       = GetParseOptions(projectElement, language, languageServices);
            var compilationOptions = CreateCompilationOptions(workspace, projectElement, language, parseOptions);
            var rootNamespace      = GetRootNamespace(workspace, compilationOptions, projectElement);

            var references = CreateReferenceList(workspace, projectElement);
            var analyzers  = CreateAnalyzerList(projectElement);

            var documents        = new List <TestHostDocument>();
            var documentElements = projectElement.Elements(DocumentElementName).ToList();

            foreach (var documentElement in documentElements)
            {
                var document = CreateDocument(
                    workspace,
                    workspaceElement,
                    documentElement,
                    exportProvider,
                    languageServices,
                    documentServiceProvider,
                    ref documentId);

                documents.Add(document);
            }

            foreach (var sourceGeneratedDocumentElement in projectElement.Elements(DocumentFromSourceGeneratorElementName))
            {
                var name = GetFileName(workspace, sourceGeneratedDocumentElement, ref documentId);

                var markupCode = sourceGeneratedDocumentElement.NormalizedValue();
                MarkupTestFile.GetPositionAndSpans(markupCode,
                                                   out var code, out var cursorPosition, out IDictionary <string, ImmutableArray <TextSpan> > spans);

                var documentFilePath = typeof(SingleFileTestGenerator).Assembly.GetName().Name + '\\' + typeof(SingleFileTestGenerator).FullName + '\\' + name;
                var document         = new TestHostDocument(exportProvider, languageServices, code, name, documentFilePath, cursorPosition, spans, isSourceGenerated: true);
                documents.Add(document);

                analyzers.Add(new TestGeneratorReference(new SingleFileTestGenerator(code, name)));
            }

            var additionalDocuments        = new List <TestHostDocument>();
            var additionalDocumentElements = projectElement.Elements(AdditionalDocumentElementName).ToList();

            foreach (var additionalDocumentElement in additionalDocumentElements)
            {
                var document = CreateDocument(
                    workspace,
                    workspaceElement,
                    additionalDocumentElement,
                    exportProvider,
                    languageServices,
                    documentServiceProvider,
                    ref documentId);

                additionalDocuments.Add(document);
            }

            var analyzerConfigDocuments = new List <TestHostDocument>();
            var analyzerConfigElements  = projectElement.Elements(AnalyzerConfigDocumentElementName).ToList();

            foreach (var analyzerConfigElement in analyzerConfigElements)
            {
                var document = CreateDocument(
                    workspace,
                    workspaceElement,
                    analyzerConfigElement,
                    exportProvider,
                    languageServices,
                    documentServiceProvider,
                    ref documentId);

                analyzerConfigDocuments.Add(document);
            }

            return(new TestHostProject(languageServices, compilationOptions, parseOptions, assemblyName, projectName, references, documents, additionalDocuments, analyzerConfigDocuments, filePath: filePath, analyzerReferences: analyzers, defaultNamespace: rootNamespace));
        }