public void VerifyResult(MetadataAsSourceFile file, string expected) { var actual = File.ReadAllText(file.FilePath).Trim(); var actualSpan = file.IdentifierLocation.SourceSpan; // Compare exact texts and verify that the location returned is exactly that // indicated by expected MarkupTestFile.GetSpan(expected, out expected, out var expectedSpan); Assert.Equal(expected, actual); Assert.Equal(expectedSpan.Start, actualSpan.Start); Assert.Equal(expectedSpan.End, actualSpan.End); }
protected async Task AssertFormatWithBaseIndentAsync(string expected, string markupCode, int baseIndentation) { MarkupTestFile.GetSpan(markupCode, out var code, out var span); await AssertFormatAsync( expected, code, new List <TextSpan> { span }, baseIndentation : baseIndentation); }
public async Task FollowTypeForwards_NestedType() { var source = @" public class C { public class D { // A change public event System.EventHandler [|E|] { add { } remove { } } } }"; var typeForwardSource = @" [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))] "; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); // Compile reference assembly var sourceText = SourceText.From(metadataSource, encoding: Encoding.UTF8); var(project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C.D.E"), buildReferenceAssembly: true); // Compile implementation assembly to a different DLL var dllFilePath = Path.Combine(path, "implementation.dll"); var sourceCodePath = Path.Combine(path, "implementation.cs"); var pdbFilePath = Path.Combine(path, "implementation.pdb"); var assemblyName = "implementation"; var workspace = TestWorkspace.Create(@$ " <Workspace> <Project Language=" "{LanguageNames.CSharp}" " CommonReferences=" "true" " ReferencesOnDisk=" "true" "> </Project> </Workspace>", composition: GetTestComposition()); var implProject = workspace.CurrentSolution.Projects.First(); CompileTestSource(dllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); // Compile type forwarding implementation DLL var typeForwardDllFilePath = Path.Combine(path, "typeforward.dll"); assemblyName = "typeforward"; implProject = implProject.AddMetadataReference(MetadataReference.CreateFromFile(dllFilePath)); sourceText = SourceText.From(typeForwardSource, Encoding.UTF8); CompileTestSource(typeForwardDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); var service = workspace.GetService <IImplementationAssemblyLookupService>(); Assert.Equal(dllFilePath, service.FollowTypeForwards(symbol, typeForwardDllFilePath, new NoDuplicatesLogger())); }); }
public void ServiceTest2() { var markupCode = @"class A { #if true [|/* test */ public|] void Test(int i, int b, int c) { } #endif }"; MarkupTestFile.GetSpan(markupCode, out var code, out var span); var root = SyntaxFactory.ParseCompilationUnit(code); var result = CSharpSyntaxTriviaService.Instance.SaveTriviaAroundSelection(root, span); var rootWithAnnotation = result.Root; // find token to replace var publicToken = rootWithAnnotation .DescendantTokens() .First(t => t.Kind() == SyntaxKind.PublicKeyword); // replace the token with new one var newRoot = rootWithAnnotation.ReplaceToken( publicToken, SyntaxFactory.Token(SyntaxKind.PrivateKeyword) ); // restore trivia around it var rootWithTriviaRestored = result.RestoreTrivia(newRoot); var expected = @"class A { #if true private void Test(int i, int b, int c) { } #endif }"; Assert.Equal(expected, rootWithTriviaRestored.ToFullString()); }
protected async Task TestAsync(string text, string expectedType, bool testNode = true, bool testPosition = true) { MarkupTestFile.GetSpan(text.NormalizeLineEndings(), out text, out var textSpan); if (testNode) { await TestWithAndWithoutSpeculativeSemanticModelAsync(text, textSpan, expectedType, useNodeStartPosition : false); } if (testPosition) { await TestWithAndWithoutSpeculativeSemanticModelAsync(text, textSpan, expectedType, useNodeStartPosition : true); } }
protected void AssertFormatWithBaseIndent(string expected, string markupCode, int baseIndentation) { string code; TextSpan span; MarkupTestFile.GetSpan(markupCode, out code, out span); AssertFormat( expected, code, new List <TextSpan> { span }, baseIndentation: baseIndentation); }
protected async Task TestAsync(string text, string expectedType, TestMode mode, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular) { MarkupTestFile.GetSpan(text.NormalizeLineEndings(), out text, out var textSpan); var document = fixture.UpdateDocument(text, sourceCodeKind); await TestWorkerAsync(document, textSpan, expectedType, mode); if (await CanUseSpeculativeSemanticModelAsync(document, textSpan.Start)) { var document2 = fixture.UpdateDocument(text, sourceCodeKind, cleanBeforeUpdate: false); await TestWorkerAsync(document2, textSpan, expectedType, mode); } }
protected void Test(string text, string expectedType, bool testNode = true, bool testPosition = true) { TextSpan textSpan; MarkupTestFile.GetSpan(text.NormalizeLineEndings(), out text, out textSpan); if (testNode) { TestWithAndWithoutSpeculativeSemanticModel(text, textSpan, expectedType, useNodeStartPosition: false); } if (testPosition) { TestWithAndWithoutSpeculativeSemanticModel(text, textSpan, expectedType, useNodeStartPosition: true); } }
private async Task TestDelegateAsync(string text, string expectedType) { MarkupTestFile.GetSpan(text, out text, out var textSpan); Document document = fixture.UpdateDocument(text, SourceCodeKind.Regular); var root = await document.GetSyntaxRootAsync(); var node = FindExpressionSyntaxFromSpan(root, textSpan); var typeInference = document.GetLanguageService <ITypeInferenceService>(); var delegateType = typeInference.InferDelegateType(await document.GetSemanticModelAsync(), node, CancellationToken.None); Assert.NotNull(delegateType); Assert.Equal(expectedType, delegateType.ToNameDisplayString()); }
protected async Task TestRenameTypeToMatchFileAsync( string originalCode, string expectedCode = null, bool expectedCodeAction = true, bool ignoreTrivia = true, string fixAllActionEquivalenceKey = null, object fixProviderData = null) { var testOptions = new TestParameters( fixAllActionEquivalenceKey: fixAllActionEquivalenceKey, fixProviderData: fixProviderData); using (var workspace = await CreateWorkspaceFromOptionsAsync(originalCode, testOptions)) { if (expectedCodeAction) { Assert.True(expectedCode != null, $"{nameof(expectedCode)} should be present if {nameof(expectedCodeAction)} is true."); var documentId = workspace.Documents[0].Id; var documentName = workspace.Documents[0].Name; MarkupTestFile.GetSpan(expectedCode, out var expectedText, out var span); var codeActionTitle = string.Format(RenameTypeCodeActionTitle, expectedText.Substring(span.Start, span.Length)); var oldSolutionAndNewSolution = await TestOperationAsync( testOptions, workspace, expectedText, codeActionTitle, ignoreTrivia); // the original source document does not exist in the new solution. var newSolution = oldSolutionAndNewSolution.Item2; var document = newSolution.GetDocument(documentId); Assert.NotNull(document); Assert.Equal(documentName, document.Name); } else { var actions = await GetCodeActionsAsync(workspace, testOptions); if (actions != null) { var renameFileAction = actions.Any(action => action.Title.StartsWith(RenameTypeCodeActionTitle)); Assert.False(renameFileAction, "Rename Type to match file name code action was not expected, but shows up."); } } } }
public async Task WindowsPdb_NullResult() { var source = @" public class C { public event System.EventHandler [|E|] { add { } remove { } } }"; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); var(project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E"), windowsPdb: true); //TODO: This should not be a null result: https://github.com/dotnet/roslyn/issues/55834 await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); }
public async Task Net6SdkLayout_WithOtherReferences() { var source = @" public class C { public void [|M|](string d) { } } "; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); var packDir = Directory.CreateDirectory(Path.Combine(path, "packs", "MyPack.Ref", "1.0", "ref", "net6.0")).FullName; var dataDir = Directory.CreateDirectory(Path.Combine(path, "packs", "MyPack.Ref", "1.0", "data")).FullName; var sharedDir = Directory.CreateDirectory(Path.Combine(path, "shared", "MyPack", "1.0")).FullName; var sourceText = SourceText.From(metadataSource, Encoding.UTF8); var(project, symbol) = await CompileAndFindSymbolAsync(packDir, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C.M"), buildReferenceAssembly: true); var workspace = TestWorkspace.Create(@$ " <Workspace> <Project Language=" "{LanguageNames.CSharp}" " CommonReferences=" "true" " ReferencesOnDisk=" "true" "> </Project> </Workspace>", composition: GetTestComposition()); var implProject = workspace.CurrentSolution.Projects.First(); // Compile implementation assembly CompileTestSource(sharedDir, sourceText, project, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); // Create FrameworkList.xml File.WriteAllText(Path.Combine(dataDir, "FrameworkList.xml"), "" " <FileList FrameworkName=" MyPack "> </FileList> " ""); await GenerateFileAndVerifyAsync(project, symbol, Location.Embedded, metadataSource.ToString(), expectedSpan, expectNullResult: false); }); }
public async Task EmptyPdb_NullResult() { var source = @" public class C { public event System.EventHandler [|E|] { add { } remove { } } }"; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); var(project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E")); // Now make the PDB a zero byte file File.WriteAllBytes(GetPdbPath(path), new byte[0]); await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); }
public async Task NoSource_NullResult() { var source = @" public class C { public event System.EventHandler [|E|] { add { } remove { } } }"; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); var(project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E")); // Now delete the source File.Delete(GetSourceFilePath(path)); await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); }
public static async Task SingleErrorTestAsync(IFormattingRule rule, string code, DiagnosticDescriptor expectedDescriptor, string expectedMessage = null) { MarkupTestFile.GetSpan(code, out code, out var expectedLocation); var actualDiagnostics = await EvaluateRuleAsync(rule, code); Assert.Collection(actualDiagnostics, diagnostic => { // Check ID specially so that we get a friendly error if the descriptor doesn't match Assert.Equal(expectedDescriptor.Id, diagnostic.Id); Assert.Same(expectedDescriptor, diagnostic.Descriptor); if (expectedMessage != null) { Assert.Equal(expectedMessage, diagnostic.GetMessage()); } Assert.Equal(expectedLocation, diagnostic.Location.SourceSpan); }); }
public void Directive_character_ranges_can_be_read() { var markupCode = @" [|#!csharp|] var x = 123; x "; MarkupTestFile.GetSpan(markupCode, out var code, out var span); var tree = CreateSubmissionParser("csharp").Parse(code); var textSpan = tree.GetRoot() .FindNode(span) .ChildTokens .OfType <DirectiveToken>() .Single() .Span; textSpan.Should().BeEquivalentTo(span); }
public async Task NoUrlFoundReturnsNull() { var source = @" public class C { public event System.EventHandler [|E|] { add { } remove { } } }"; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); var(project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E")); // Move the source file to a path that only our fake debugger service knows about var sourceFilePath = Path.Combine(path, "SourceLink.cs"); File.Move(GetSourceFilePath(path), sourceFilePath); var sourceLinkService = new Lazy <ISourceLinkService?>(() => new TestSourceLinkService(sourceFilePath: sourceFilePath)); var service = new PdbSourceDocumentLoaderService(sourceLinkService, logger: null); var sourceDocument = new SourceDocument("goo.cs", Text.SourceHashAlgorithm.None, default, null, SourceLinkUrl: null);
public async Task CorruptPdb_NullResult() { var source = @" public class C { public event System.EventHandler [|E|] { add { } remove { } } }"; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); var(project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E")); // The first four bytes of this are BSJB so it is identified as a portable PDB. // The next two bytes are unimportant, they're just not valid PDB data. var corruptPdb = new byte[] { 66, 83, 74, 66, 68, 87 }; File.WriteAllBytes(GetPdbPath(path), corruptPdb); await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); }
public async Task Net6SdkLayout_PacksInPath() { var source = @" public class C { // A change public event System.EventHandler [|E|] { add { } remove { } } }"; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); path = Path.Combine(path, "packs", "installed", "here"); var packDir = Directory.CreateDirectory(Path.Combine(path, "packs", "MyPack.Ref", "1.0", "ref", "net6.0")).FullName; var dataDir = Directory.CreateDirectory(Path.Combine(path, "packs", "MyPack.Ref", "1.0", "data")).FullName; var sharedDir = Directory.CreateDirectory(Path.Combine(path, "shared", "MyPack", "1.0")).FullName; // Compile reference assembly var sourceText = SourceText.From(metadataSource, encoding: Encoding.UTF8); var(project, symbol) = await CompileAndFindSymbolAsync(packDir, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C.E"), buildReferenceAssembly: true); // Compile implementation assembly CompileTestSource(sharedDir, sourceText, project, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); // Create FrameworkList.xml File.WriteAllText(Path.Combine(dataDir, "FrameworkList.xml"), "" " <FileList FrameworkName=" MyPack "> </FileList> " ""); var workspace = (TestWorkspace)project.Solution.Workspace; var service = workspace.GetService <IImplementationAssemblyLookupService>(); Assert.True(service.TryFindImplementationAssemblyPath(GetDllPath(packDir), out var implementationDll)); Assert.Equal(GetDllPath(sharedDir), implementationDll); }); }
public void VerifyResult(MetadataAsSourceFile file, string expected, bool ignoreTrivia = true) { var actual = File.ReadAllText(file.FilePath).Trim(); var actualSpan = file.IdentifierLocation.SourceSpan; if (ignoreTrivia) { // Compare tokens and verify location relative to the generated tokens expected = GetSpaceSeparatedTokens(expected); actual = GetSpaceSeparatedTokens(actual.Insert(actualSpan.Start, "[|").Insert(actualSpan.End + 2, "|]")); } else { // Compare exact texts and verify that the location returned is exactly that // indicated by expected MarkupTestFile.GetSpan(expected.TrimStart().TrimEnd(), out expected, out var expectedSpan); Assert.Equal(expectedSpan.Start, actualSpan.Start); Assert.Equal(expectedSpan.End, actualSpan.End); } Assert.Equal(expected, actual); }
protected async Task TestRenameTypeToMatchFileAsync( string originalCode, string expectedCode = null, bool expectedCodeAction = true, object fixProviderData = null) { var testOptions = new TestParameters(fixProviderData: fixProviderData); using (var workspace = CreateWorkspaceFromOptions(originalCode, testOptions)) { if (expectedCodeAction) { Assert.True(expectedCode != null, $"{nameof(expectedCode)} should be present if {nameof(expectedCodeAction)} is true."); var documentId = workspace.Documents[0].Id; var documentName = workspace.Documents[0].Name; MarkupTestFile.GetSpan(expectedCode, out var expectedText, out var span); var codeActionTitle = string.Format(RenameTypeCodeActionTitle, expectedText.Substring(span.Start, span.Length)); var oldSolutionAndNewSolution = await TestOperationAsync( testOptions, workspace, expectedText, codeActionTitle); // the original source document does not exist in the new solution. var newSolution = oldSolutionAndNewSolution.Item2; var document = newSolution.GetDocument(documentId); Assert.NotNull(document); Assert.Equal(documentName, document.Name); } else { var(actions, _) = await GetCodeActionsAsync(workspace, testOptions); if (actions.Length > 0) { var renameFileAction = actions.Any(static (action, self) => action.Title.StartsWith(self.RenameTypeCodeActionTitle), this);
protected static async Task TestAsync( string path, Location pdbLocation, Location sourceLocation, string metadataSource, Func <Compilation, ISymbol> symbolMatcher, string[]?preprocessorSymbols, bool buildReferenceAssembly, bool expectNullResult) { MarkupTestFile.GetSpan(metadataSource, out var source, out var expectedSpan); var(project, symbol) = await CompileAndFindSymbolAsync( path, pdbLocation, sourceLocation, source, symbolMatcher, preprocessorSymbols, buildReferenceAssembly, windowsPdb : false); await GenerateFileAndVerifyAsync(project, symbol, sourceLocation, source, expectedSpan, expectNullResult); }
internal static async Task TestGenerateFromSourceSymbolAsync( string symbolSource, string initial, string expected, bool onlyGenerateMembers = false, CodeGenerationOptions codeGenerationOptions = default(CodeGenerationOptions), bool compareTokens = true, string forceLanguage = null) { using (var context = await TestContext.CreateAsync(initial, expected, compareTokens, forceLanguage)) { TextSpan destSpan = new TextSpan(); MarkupTestFile.GetSpan(symbolSource.NormalizeLineEndings(), out symbolSource, out destSpan); var projectId = ProjectId.CreateNewId(); var documentId = DocumentId.CreateNewId(projectId); var semanticModel = await context.Solution .AddProject(projectId, "GenerationSource", "GenerationSource", TestContext.GetLanguage(symbolSource)) .AddDocument(documentId, "Source.cs", symbolSource) .GetDocument(documentId) .GetSemanticModelAsync(); var symbol = context.GetSelectedSymbol <INamespaceOrTypeSymbol>(destSpan, semanticModel); var destination = context.GetDestination(); if (destination.IsType) { var members = onlyGenerateMembers ? symbol.GetMembers().ToArray() : new[] { symbol }; context.Result = await context.Service.AddMembersAsync(context.Solution, (INamedTypeSymbol)destination, members, codeGenerationOptions); } else { context.Result = await context.Service.AddNamespaceOrTypeAsync(context.Solution, (INamespaceSymbol)destination, symbol, codeGenerationOptions); } } }
public async Task FollowTypeForwards_MultipleHops_Cache() { var source = @" public class C { // A change public event System.EventHandler [|E|] { add { } remove { } } }"; var typeForwardSource = @" [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))] "; await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); // Compile reference assembly var sourceText = SourceText.From(metadataSource, encoding: Encoding.UTF8); var(project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, sourceText, c => c.GetMember("C.E"), buildReferenceAssembly: true); // Compile implementation assembly to a different DLL var dllFilePath = Path.Combine(path, "implementation.dll"); var sourceCodePath = Path.Combine(path, "implementation.cs"); var pdbFilePath = Path.Combine(path, "implementation.pdb"); var assemblyName = "implementation"; var workspace = TestWorkspace.Create(@$ " <Workspace> <Project Language=" "{LanguageNames.CSharp}" " CommonReferences=" "true" " ReferencesOnDisk=" "true" "> </Project> </Workspace>", composition: GetTestComposition()); var implProject = workspace.CurrentSolution.Projects.First(); CompileTestSource(dllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); // Compile type forwarding implementation DLL var typeForwardDllFilePath = Path.Combine(path, "typeforward.dll"); assemblyName = "typeforward"; implProject = workspace.CurrentSolution.Projects.First().AddMetadataReference(MetadataReference.CreateFromFile(dllFilePath)); var typeForwardSourceText = SourceText.From(typeForwardSource, Encoding.UTF8); CompileTestSource(typeForwardDllFilePath, sourceCodePath, pdbFilePath, assemblyName, typeForwardSourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); // Now compile a new implementation in realimplementation.dll var realImplementationDllFilePath = Path.Combine(path, "realimplementation.dll"); assemblyName = "realimplementation"; implProject = workspace.CurrentSolution.Projects.First(); CompileTestSource(realImplementationDllFilePath, sourceCodePath, pdbFilePath, assemblyName, sourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); // Now compile a new implementation.dll that typeforwards to realimplementation.dll assemblyName = "implementation"; implProject = workspace.CurrentSolution.Projects.First().AddMetadataReference(MetadataReference.CreateFromFile(realImplementationDllFilePath)); CompileTestSource(dllFilePath, sourceCodePath, pdbFilePath, assemblyName, typeForwardSourceText, implProject, Location.Embedded, Location.Embedded, buildReferenceAssembly: false, windowsPdb: false); var service = workspace.GetService <IImplementationAssemblyLookupService>(); var foundImplementationFilePath = service.FollowTypeForwards(symbol, typeForwardDllFilePath, new NoDuplicatesLogger()); Assert.Equal(realImplementationDllFilePath, foundImplementationFilePath); // We need the DLLs to exist, in order for some checks to pass correct, but to ensure // that the file isn't read, we just zero it out. File.WriteAllBytes(typeForwardDllFilePath, Array.Empty <byte>()); File.WriteAllBytes(realImplementationDllFilePath, Array.Empty <byte>()); File.WriteAllBytes(dllFilePath, Array.Empty <byte>()); foundImplementationFilePath = service.FollowTypeForwards(symbol, typeForwardDllFilePath, new NoDuplicatesLogger()); Assert.Equal(realImplementationDllFilePath, foundImplementationFilePath); }); }