diff --git a/Roslyn-SDK.sln b/Roslyn-SDK.sln
index 5924613d9d..a1bc3103d1 100644
--- a/Roslyn-SDK.sln
+++ b/Roslyn-SDK.sln
@@ -149,6 +149,8 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.Visu
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VisualStudio.Roslyn.SDK", "VisualStudio.Roslyn.SDK", "{A3AF556C-276C-49BA-A9ED-E7D42FECAA46}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.SDK.IntegrationTests", "tests\VisualStudio.Roslyn.SDK\Roslyn.SDK.IntegrationTests\Roslyn.SDK.IntegrationTests.csproj", "{6DBBFF7B-2C28-47D7-8618-B6085044E38D}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.SDK.UnitTests", "tests\VisualStudio.Roslyn.SDK\Roslyn.SDK.UnitTests\Roslyn.SDK.UnitTests.csproj", "{11B1F856-9025-4A4C-B90D-B1237743B672}"
EndProject
Global
@@ -421,6 +423,10 @@ Global
{023B21F8-09EC-4A67-8AAA-3D110231E7EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{023B21F8-09EC-4A67-8AAA-3D110231E7EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{023B21F8-09EC-4A67-8AAA-3D110231E7EB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6DBBFF7B-2C28-47D7-8618-B6085044E38D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6DBBFF7B-2C28-47D7-8618-B6085044E38D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6DBBFF7B-2C28-47D7-8618-B6085044E38D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6DBBFF7B-2C28-47D7-8618-B6085044E38D}.Release|Any CPU.Build.0 = Release|Any CPU
{11B1F856-9025-4A4C-B90D-B1237743B672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11B1F856-9025-4A4C-B90D-B1237743B672}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11B1F856-9025-4A4C-B90D-B1237743B672}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -501,6 +507,7 @@ Global
{4617ED77-9564-4A06-8F9B-92E5C5523FE1} = {9905147E-CC1F-42A0-BD27-05586C583DF7}
{023B21F8-09EC-4A67-8AAA-3D110231E7EB} = {9905147E-CC1F-42A0-BD27-05586C583DF7}
{A3AF556C-276C-49BA-A9ED-E7D42FECAA46} = {8C343846-5F9F-4033-9B52-B44C61962449}
+ {6DBBFF7B-2C28-47D7-8618-B6085044E38D} = {A3AF556C-276C-49BA-A9ED-E7D42FECAA46}
{11B1F856-9025-4A4C-B90D-B1237743B672} = {A3AF556C-276C-49BA-A9ED-E7D42FECAA46}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
diff --git a/eng/Versions.props b/eng/Versions.props
index 9861332323..a531698656 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -33,11 +33,15 @@
16.4.280
7.10.6071
16.5.29911.84
+ 16.5.29911.84
7.10.6072
8.0.50728
9.0.30730
10.0.30320
11.0.61031
+ 12.1.30329
+ 14.3.26929
+ 15.7.1
16.4.280
16.4.280
7.10.6071
@@ -45,6 +49,7 @@
16.4.280
16.5.29903.186
16.5.132
+ 5.6.0
2.3.99
1.3.1
@@ -55,6 +60,7 @@
2.6.1
3.3.1
1.2.7
+ 0.1.49-beta
2.9.8
1.2.0-beta.164
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKCodeFixTemplateWizard.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKCodeFixTemplateWizard.cs
new file mode 100644
index 0000000000..057f0ad344
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKCodeFixTemplateWizard.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using EnvDTE;
+using VSLangProj;
+
+public class RoslynSDKCodeFixTemplateWizard : RoslynSDKChildTemplateWizard
+{
+ public static Project Project { get; private set; }
+
+ public override void OnProjectFinishedGenerating(Project project)
+ {
+ Project = project;
+
+ // There is no good way for the test project to reference the main project, so we will use the wizard.
+#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
+ if (project.Object is VSProject vsProject)
+#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread
+ {
+ var referenceProject = vsProject.References.AddProject(RoslynSDKAnalyzerTemplateWizard.Project);
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKPackageTemplateWizard.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKPackageTemplateWizard.cs
new file mode 100644
index 0000000000..6d3815b6ba
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKPackageTemplateWizard.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using EnvDTE;
+using VSLangProj;
+
+public class RoslynSDKPackageTemplateWizard : RoslynSDKChildTemplateWizard
+{
+ public override void OnProjectFinishedGenerating(Project project)
+ {
+ // There is no good way for the test project to reference the main project, so we will use the wizard.
+#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
+ if (project.Object is VSProject vsProject)
+#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread
+ {
+ _ = vsProject.References.AddProject(RoslynSDKAnalyzerTemplateWizard.Project);
+ _ = vsProject.References.AddProject(RoslynSDKCodeFixTemplateWizard.Project);
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKTestTemplateWizard.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKTestTemplateWizard.cs
index 3ae6353978..821b331015 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKTestTemplateWizard.cs
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKTestTemplateWizard.cs
@@ -12,7 +12,8 @@ public override void OnProjectFinishedGenerating(Project project)
if (project.Object is VSProject vsProject)
#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread
{
- var referenceProject = vsProject.References.AddProject(RoslynSDKAnalyzerTemplateWizard.Project);
+ _ = vsProject.References.AddProject(RoslynSDKAnalyzerTemplateWizard.Project);
+ _ = vsProject.References.AddProject(RoslynSDKCodeFixTemplateWizard.Project);
}
}
}
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/CSharpDiagnostic.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/CSharpDiagnostic.vstemplate
index 33882df70c..9cbb893ee5 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/CSharpDiagnostic.vstemplate
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/CSharpDiagnostic.vstemplate
@@ -29,7 +29,13 @@
Modifying it requires changes to the wizard code.-->
- ProjectTemplates\CSharp\Diagnostic\Analyzer\DiagnosticAnalyzer.vstemplate
+ ProjectTemplates\CSharp\Diagnostic\Analyzer\DiagnosticAnalyzer.vstemplate
+
+
+ ProjectTemplates\CSharp\Diagnostic\CodeFix\CodeFixProvider.vstemplate
+
+
+ ProjectTemplates\CSharp\Diagnostic\Package\Package.vstemplate
ProjectTemplates\CSharp\Diagnostic\Test\Test.vstemplate
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.csproj
index 8e93db2978..b50f469c83 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.csproj
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.csproj
@@ -2,30 +2,15 @@
netstandard2.0
- false
- true
- True
-
+ false
-
- $safeprojectname$
- 1.0.0.0
- $username$
- http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE
- http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE
- http://ICON_URL_HERE_OR_DELETE_THIS_LINE
- http://REPOSITORY_URL_HERE_OR_DELETE_THIS_LINE
- false
- $safeprojectname$
- Summary of changes made in this release of the package.
- Copyright
- $safeprojectname$, analyzers
- true
+
+ *$(MSBuildProjectFullPath)*
-
+
@@ -33,9 +18,4 @@
-
-
-
-
-
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate
index 47b9f22045..6a305f4e96 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate
@@ -19,11 +19,8 @@
DiagnosticAnalyzer.cs
- CodeFixProvider.cs
Resources.resx
Resources.Designer.cs
- install.ps1
- uninstall.ps1
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/CodeFixProvider.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.cs
similarity index 95%
rename from src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/CodeFixProvider.cs
rename to src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.cs
index 6380fb5929..cee0d31814 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/CodeFixProvider.cs
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
@@ -18,8 +18,6 @@ namespace $saferootprojectname$
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof($saferootidentifiername$CodeFixProvider)), Shared]
public class $saferootidentifiername$CodeFixProvider : CodeFixProvider
{
- private const string title = "Make uppercase";
-
public sealed override ImmutableArray FixableDiagnosticIds
{
get { return ImmutableArray.Create($saferootidentifiername$Analyzer.DiagnosticId); }
@@ -45,9 +43,9 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
CodeAction.Create(
- title: title,
+ title: CodeFixResources.CodeFixTitle,
createChangedSolution: c => MakeUppercaseAsync(context.Document, declaration, c),
- equivalenceKey: title),
+ equivalenceKey: nameof(CodeFixResources.CodeFixTitle)),
diagnostic);
}
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.csproj
new file mode 100644
index 0000000000..1c091606ec
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.csproj
@@ -0,0 +1,18 @@
+
+
+
+ netstandard2.0
+ false
+ $saferootprojectname$
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.vstemplate
new file mode 100644
index 0000000000..267bf2505a
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixProvider.vstemplate
@@ -0,0 +1,30 @@
+
+
+
+ CodeFixProvider
+ <No description available>
+
+ CSharp
+ 2.0
+ 952
+ bb967cab-2ca5-4dac-8809-65b2b28a6350
+ true
+ true
+ CodeFixProvider
+ true
+ true
+
+
+
+ CodeFixProvider.cs
+ CodeFixResources.resx
+ CodeFixResources.Designer.cs
+
+
+
+ Roslyn.SDK.Template.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
+ RoslynSDKCodeFixTemplateWizard
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixResources.Designer.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixResources.Designer.cs
new file mode 100644
index 0000000000..07e319a98e
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixResources.Designer.cs
@@ -0,0 +1,84 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.0
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace $saferootprojectname$
+{
+ using System;
+ using System.Reflection;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class CodeFixResources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal CodeFixResources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if (object.ReferenceEquals(resourceMan, null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("$saferootprojectname$.CodeFixResources", typeof(CodeFixResources).GetTypeInfo().Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Make uppercase.
+ ///
+ internal static string CodeFixTitle
+ {
+ get
+ {
+ return ResourceManager.GetString("CodeFixTitle", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixResources.resx b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixResources.resx
new file mode 100644
index 0000000000..97abe68945
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/CodeFix/CodeFixResources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Make uppercase
+ The title of the code fix.
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/Package.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/Package.csproj
new file mode 100644
index 0000000000..b37b009b41
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/Package.csproj
@@ -0,0 +1,39 @@
+
+
+
+ netstandard2.0
+ false
+ true
+ true
+
+
+
+ $saferootprojectname$
+ 1.0.0.0
+ $username$
+ http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE
+ http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE
+ http://ICON_URL_HERE_OR_DELETE_THIS_LINE
+ http://REPOSITORY_URL_HERE_OR_DELETE_THIS_LINE
+ false
+ $saferootprojectname$
+ Summary of changes made in this release of the package.
+ Copyright
+ $saferootprojectname$, analyzers
+ true
+
+ $(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/Package.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/Package.vstemplate
new file mode 100644
index 0000000000..97094dcb69
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/Package.vstemplate
@@ -0,0 +1,29 @@
+
+
+
+ Package
+ <No description available>
+
+ CSharp
+ 2.0
+ 952
+ bb967cab-2ca5-4dac-8809-65b2b28a6350
+ true
+ true
+ Package
+ true
+ true
+
+
+
+ install.ps1
+ uninstall.ps1
+
+
+
+ Roslyn.SDK.Template.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
+ RoslynSDKPackageTemplateWizard
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/install.ps1 b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/install.ps1
similarity index 100%
rename from src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/install.ps1
rename to src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/install.ps1
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/uninstall.ps1 b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/uninstall.ps1
similarity index 100%
rename from src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Analyzer/uninstall.ps1
rename to src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Package/uninstall.ps1
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Vsix/source.extension.vsixmanifest b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Vsix/source.extension.vsixmanifest
index 71b6305026..5412f6779f 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Vsix/source.extension.vsixmanifest
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Vsix/source.extension.vsixmanifest
@@ -14,6 +14,8 @@
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/Diagnostic.vbproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/Diagnostic.vbproj
index d71b112969..d151c678fb 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/Diagnostic.vbproj
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/Diagnostic.vbproj
@@ -2,40 +2,20 @@
netstandard2.0
- false
- true
- True
-
+ false
-
- $safeprojectname$
- 1.0.0.0
- $username$
- http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE
- http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE
- http://ICON_URL_HERE_OR_DELETE_THIS_LINE
- http://REPOSITORY_URL_HERE_OR_DELETE_THIS_LINE
- false
- $safeprojectname$
- Summary of changes made in this release of the package.
- Copyright
- $safeprojectname$, analyzers
- true
+
+ *$(MSBuildProjectFullPath)*
-
-
-
-
-
-
+
-
-
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate
index 824440cdfe..632f6de039 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/DiagnosticAnalyzer.vstemplate
@@ -19,11 +19,8 @@
DiagnosticAnalyzer.vb
- CodeFixProvider.vb
Resources.resx
Resources.Designer.vb
- install.ps1
- uninstall.ps1
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/CodeFixProvider.vb b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vb
similarity index 96%
rename from src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/CodeFixProvider.vb
rename to src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vb
index d7809633cd..0c722c5667 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/CodeFixProvider.vb
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vb
@@ -17,8 +17,6 @@ Imports Microsoft.CodeAnalysis.Text
Public Class $saferootidentifiername$CodeFixProvider
Inherits CodeFixProvider
- Private Const title As String = "Make uppercase"
-
Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String)
Get
Return ImmutableArray.Create($saferootidentifiername$Analyzer.DiagnosticId)
@@ -44,9 +42,9 @@ Public Class $saferootidentifiername$CodeFixProvider
' Register a code action that will invoke the fix.
context.RegisterCodeFix(
CodeAction.Create(
- title:=title,
+ title:=My.Resources.CodeFixTitle,
createChangedSolution:=Function(c) MakeUppercaseAsync(context.Document, declaration, c),
- equivalenceKey:=title),
+ equivalenceKey:=NameOf(My.Resources.CodeFixTitle)),
diagnostic)
End Function
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vbproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vbproj
new file mode 100644
index 0000000000..448fff5398
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vbproj
@@ -0,0 +1,18 @@
+
+
+
+ netstandard2.0
+ false
+ $saferootprojectname$
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vstemplate
new file mode 100644
index 0000000000..113c0562c3
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixProvider.vstemplate
@@ -0,0 +1,30 @@
+
+
+
+ CodeFixProvider
+ <No description available>
+
+ VisualBasic
+ 2.0
+ 1000
+ bb967cab-2ca5-4dac-8809-65b2b28a6350
+ true
+ true
+ CodeFixProvider
+ true
+ true
+
+
+
+ CodeFixProvider.vb
+ CodeFixResources.resx
+ CodeFixResources.Designer.vb
+
+
+
+ Roslyn.SDK.Template.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
+ RoslynSDKCodeFixTemplateWizard
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixResources.Designer.vb b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixResources.Designer.vb
new file mode 100644
index 0000000000..ea770a00dc
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixResources.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.0
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+Imports System
+Imports System.Reflection
+
+Namespace My.Resources
+
+ 'This class was auto-generated by the StronglyTypedResourceBuilder
+ 'class via a tool like ResGen or Visual Studio.
+ 'To add or remove a member, edit your .ResX file then rerun ResGen
+ 'with the /str option, or rebuild your VS project.
+ '''
+ ''' A strongly-typed resource class, for looking up localized strings, etc.
+ '''
+
+ Friend Module CodeFixResources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Returns the cached ResourceManager instance used by this class.
+ '''
+
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("$saferootprojectname$.CodeFixResources", GetType(CodeFixResources).GetTypeInfo.Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Overrides the current thread's CurrentUICulture property for all
+ ''' resource lookups using this strongly typed resource class.
+ '''
+
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set
+ resourceCulture = Value
+ End Set
+ End Property
+
+ '''
+ ''' Looks up a localized string similar to Make uppercase.
+ '''
+ Friend ReadOnly Property CodeFixTitle() As String
+ Get
+ Return ResourceManager.GetString("CodeFixTitle", resourceCulture)
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixResources.resx b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixResources.resx
new file mode 100644
index 0000000000..d7172bdc70
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/CodeFix/CodeFixResources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Make uppercase
+ The title of the code fix.
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/Package.vbproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/Package.vbproj
new file mode 100644
index 0000000000..86005e4554
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/Package.vbproj
@@ -0,0 +1,39 @@
+
+
+
+ netstandard2.0
+ false
+ true
+ true
+
+
+
+ $saferootprojectname$
+ 1.0.0.0
+ $username$
+ http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE
+ http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE
+ http://ICON_URL_HERE_OR_DELETE_THIS_LINE
+ http://REPOSITORY_URL_HERE_OR_DELETE_THIS_LINE
+ false
+ $saferootprojectname$
+ Summary of changes made in this release of the package.
+ Copyright
+ $saferootprojectname$, analyzers
+ true
+
+ $(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/Package.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/Package.vstemplate
new file mode 100644
index 0000000000..fdf0615503
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/Package.vstemplate
@@ -0,0 +1,29 @@
+
+
+
+ Package
+ <No description available>
+
+ VisualBasic
+ 2.0
+ 1000
+ bb967cab-2ca5-4dac-8809-65b2b28a6350
+ true
+ true
+ Package
+ true
+ true
+
+
+
+ install.ps1
+ uninstall.ps1
+
+
+
+ Roslyn.SDK.Template.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
+ RoslynSDKPackageTemplateWizard
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/install.ps1 b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/install.ps1
similarity index 100%
rename from src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/install.ps1
rename to src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/install.ps1
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/uninstall.ps1 b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/uninstall.ps1
similarity index 100%
rename from src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Analyzer/uninstall.ps1
rename to src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Package/uninstall.ps1
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Vsix/source.extension.vsixmanifest b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Vsix/source.extension.vsixmanifest
index 3ad382c546..b5d1aa8449 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Vsix/source.extension.vsixmanifest
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Vsix/source.extension.vsixmanifest
@@ -14,6 +14,8 @@
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/VBDiagnostic.vstemplate b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/VBDiagnostic.vstemplate
index afee41846a..bf6f5d9a63 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/VBDiagnostic.vstemplate
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/VBDiagnostic.vstemplate
@@ -31,6 +31,12 @@
ProjectTemplates\VisualBasic\Diagnostic\Analyzer\DiagnosticAnalyzer.vstemplate
+
+ ProjectTemplates\VisualBasic\Diagnostic\CodeFix\CodeFixProvider.vstemplate
+
+
+ ProjectTemplates\VisualBasic\Diagnostic\Package\Package.vstemplate
+
ProjectTemplates\VisualBasic\Diagnostic\Test\Test.vstemplate
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/AbstractIdeIntegrationTest.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/AbstractIdeIntegrationTest.cs
new file mode 100644
index 0000000000..d9cea4125d
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/AbstractIdeIntegrationTest.cs
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+using Microsoft.CodeAnalysis.Testing.InProcess;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Threading;
+using Xunit;
+using Task = System.Threading.Tasks.Task;
+
+namespace Microsoft.CodeAnalysis.Testing
+{
+ [VsTestSettings(UIThread = true, Version = "2019")]
+ public abstract class AbstractIdeIntegrationTest : IAsyncLifetime, IDisposable
+ {
+ ///
+ /// A long timeout used to avoid hangs in tests, where a test failure manifests as an operation never occurring.
+ ///
+ public static readonly TimeSpan HangMitigatingTimeout = TimeSpan.FromMinutes(1);
+
+ private JoinableTaskContext? _joinableTaskContext;
+ private JoinableTaskCollection? _joinableTaskCollection;
+ private JoinableTaskFactory? _joinableTaskFactory;
+
+ private TestServices? _testServices;
+
+ private CancellationTokenSource _hangMitigatingCancellationTokenSource;
+
+ protected AbstractIdeIntegrationTest()
+ {
+ Assert.True(Application.Current.Dispatcher.CheckAccess());
+
+ JoinableTaskContext = ThreadHelper.JoinableTaskContext;
+
+ _hangMitigatingCancellationTokenSource = new CancellationTokenSource(HangMitigatingTimeout);
+ }
+
+ [NotNull]
+ protected JoinableTaskContext? JoinableTaskContext
+ {
+ get
+ {
+ return _joinableTaskContext ?? throw new InvalidOperationException();
+ }
+
+ private set
+ {
+ if (value == _joinableTaskContext)
+ {
+ return;
+ }
+
+ if (value is null)
+ {
+ _joinableTaskContext = null;
+ _joinableTaskCollection = null;
+ _joinableTaskFactory = null;
+ }
+ else
+ {
+ _joinableTaskContext = value;
+ _joinableTaskCollection = value.CreateCollection();
+ _joinableTaskFactory = value.CreateFactory(_joinableTaskCollection).WithPriority(Application.Current.Dispatcher, DispatcherPriority.Background);
+ }
+ }
+ }
+
+ [NotNull]
+ protected TestServices? TestServices
+ {
+ get
+ {
+ return _testServices ?? throw new InvalidOperationException();
+ }
+
+ private set
+ {
+ _testServices = value;
+ }
+ }
+
+ protected JoinableTaskFactory JoinableTaskFactory
+ => _joinableTaskFactory ?? throw new InvalidOperationException();
+
+ protected CancellationToken HangMitigatingCancellationToken
+ => _hangMitigatingCancellationTokenSource.Token;
+
+ public virtual async Task InitializeAsync()
+ {
+ TestServices = await CreateTestServicesAsync();
+ }
+
+ public virtual async Task DisposeAsync()
+ {
+ if (_joinableTaskCollection is object)
+ {
+ await _joinableTaskCollection.JoinTillEmptyAsync();
+ }
+
+ JoinableTaskContext = null;
+ }
+
+ public virtual void Dispose()
+ {
+ }
+
+ protected virtual async Task CreateTestServicesAsync()
+ => await TestServices.CreateAsync(JoinableTaskFactory);
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/CreateProjectTests.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/CreateProjectTests.cs
new file mode 100644
index 0000000000..cd3e0b6ee8
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/CreateProjectTests.cs
@@ -0,0 +1,158 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Threading;
+using Xunit;
+using Task = System.Threading.Tasks.Task;
+
+namespace Microsoft.CodeAnalysis.Testing
+{
+ public class CreateProjectTests : AbstractIdeIntegrationTest
+ {
+ public override async Task DisposeAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ await TestServices.SolutionExplorer.CloseSolutionAsync();
+
+ await base.DisposeAsync();
+ }
+
+ [VsFact]
+ public async Task CreateFromTemplateAsync()
+ {
+ await TestServices.SolutionExplorer.CreateSolutionAsync(nameof(CreateProjectTests));
+ await TestServices.SolutionExplorer.AddProjectAsync("TestProj", WellKnownProjectTemplates.ClassLibrary, languageName: LanguageNames.CSharp);
+ await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
+
+ await TestServices.Editor.SetTextAsync(@"using System");
+
+ var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAsync(waitForBuildToFinish: true);
+ Assert.Equal("========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========", buildSummary);
+
+ await TestServices.ErrorList.ShowBuildErrorsAsync();
+
+ // Verify that intentional errors get validated by the test
+ var errors = await TestServices.ErrorList.GetBuildErrorsAsync(__VSERRORCATEGORY.EC_ERROR);
+ var expected = "(Compiler) Class1.cs(1, 13): error CS1002: ; expected";
+ new XUnitVerifier().EqualOrDiff(expected, string.Join(Environment.NewLine, errors));
+ Assert.Equal(1, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_ERROR));
+ }
+
+ [VsFact]
+ public async Task CreateAnalyzerFromCSharpTemplateAsync()
+ {
+ await TestServices.SolutionExplorer.CreateSolutionAsync(nameof(CreateProjectTests));
+ await TestServices.SolutionExplorer.AddProjectAsync("TestProj", "Microsoft.CSharp.Analyzer", languageName: LanguageNames.CSharp);
+ await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
+
+ var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAsync(waitForBuildToFinish: true);
+ Assert.Equal("========== Build: 5 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary);
+
+ await TestServices.ErrorList.ShowBuildErrorsAsync();
+
+ var errors = await TestServices.ErrorList.GetBuildErrorsAsync(__VSERRORCATEGORY.EC_ERROR);
+ new XUnitVerifier().EqualOrDiff(string.Empty, string.Join(Environment.NewLine, errors));
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_ERROR));
+
+ // Currently have two analyzer warnings in the template.
+ var warnings = await TestServices.ErrorList.GetBuildErrorsAsync(__VSERRORCATEGORY.EC_WARNING);
+ var expected = @"(Compiler) TestProjAnalyzer.cs(29, 57): warning RS1025: Configure generated code analysis
+(Compiler) TestProjAnalyzer.cs(29, 57): warning RS1026: Enable concurrent execution";
+ new XUnitVerifier().EqualOrDiff(expected, string.Join(Environment.NewLine, warnings));
+ Assert.Equal(2, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_WARNING));
+ }
+
+ [VsFact]
+ public async Task CreateRefactoringFromCSharpTemplateAsync()
+ {
+ await TestServices.SolutionExplorer.CreateSolutionAsync(nameof(CreateProjectTests));
+ await TestServices.SolutionExplorer.AddProjectAsync("TestProj", "Microsoft.CSharp.CodeRefactoring", languageName: LanguageNames.CSharp);
+ await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
+
+ var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAsync(waitForBuildToFinish: true);
+ Assert.Equal("========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary);
+
+ await TestServices.ErrorList.ShowBuildErrorsAsync();
+
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_ERROR));
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_WARNING));
+ }
+
+ [VsFact]
+ public async Task CreateStandaloneToolFromCSharpTemplateAsync()
+ {
+ await TestServices.SolutionExplorer.CreateSolutionAsync(nameof(CreateProjectTests));
+ await TestServices.SolutionExplorer.AddProjectAsync("TestProj", "Microsoft.CSharp.StandaloneCodeAnalysis", languageName: LanguageNames.CSharp);
+ await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
+
+ var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAsync(waitForBuildToFinish: true);
+ Assert.Equal("========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary);
+
+ await TestServices.ErrorList.ShowBuildErrorsAsync();
+
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_ERROR));
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_WARNING));
+ }
+
+ [VsFact]
+ public async Task CreateAnalyzerFromVisualBasicTemplateAsync()
+ {
+ await TestServices.SolutionExplorer.CreateSolutionAsync(nameof(CreateProjectTests));
+ await TestServices.SolutionExplorer.AddProjectAsync("TestProj", "Microsoft.VisualBasic.Analyzer", languageName: LanguageNames.VisualBasic);
+ await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
+
+ var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAsync(waitForBuildToFinish: true);
+ Assert.Equal("========== Build: 5 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary);
+
+ await TestServices.ErrorList.ShowBuildErrorsAsync();
+
+ var errors = await TestServices.ErrorList.GetBuildErrorsAsync(__VSERRORCATEGORY.EC_ERROR);
+ new XUnitVerifier().EqualOrDiff(string.Empty, string.Join(Environment.NewLine, errors));
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_ERROR));
+
+ // Currently have two analyzer warnings in the template.
+ var warnings = await TestServices.ErrorList.GetBuildErrorsAsync(__VSERRORCATEGORY.EC_WARNING);
+ var expected = @"(Compiler) TestProjAnalyzer.vb(32, 37): warning RS1025: Configure generated code analysis
+(Compiler) TestProjAnalyzer.vb(32, 37): warning RS1026: Enable concurrent execution";
+ new XUnitVerifier().EqualOrDiff(expected, string.Join(Environment.NewLine, warnings));
+ Assert.Equal(2, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_WARNING));
+ }
+
+ [VsFact]
+ public async Task CreateRefactoringFromVisualBasicTemplateAsync()
+ {
+ await TestServices.SolutionExplorer.CreateSolutionAsync(nameof(CreateProjectTests));
+ await TestServices.SolutionExplorer.AddProjectAsync("TestProj", "Microsoft.VisualBasic.CodeRefactoring", languageName: LanguageNames.VisualBasic);
+ await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
+
+ var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAsync(waitForBuildToFinish: true);
+ Assert.Equal("========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary);
+
+ await TestServices.ErrorList.ShowBuildErrorsAsync();
+
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_ERROR));
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_WARNING));
+ }
+
+ [VsFact]
+ public async Task CreateStandaloneToolFromVisualBasicTemplateAsync()
+ {
+ await TestServices.SolutionExplorer.CreateSolutionAsync(nameof(CreateProjectTests));
+ await TestServices.SolutionExplorer.AddProjectAsync("TestProj", "Microsoft.VisualBasic.StandaloneCodeAnalysis", languageName: LanguageNames.VisualBasic);
+ await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken);
+
+ var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAsync(waitForBuildToFinish: true);
+ Assert.Equal("========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary);
+
+ await TestServices.ErrorList.ShowBuildErrorsAsync();
+
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_ERROR));
+ Assert.Equal(0, await TestServices.ErrorList.GetErrorCountAsync(__VSERRORCATEGORY.EC_WARNING));
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/EditorInProcess.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/EditorInProcess.cs
new file mode 100644
index 0000000000..da5a38bde2
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/EditorInProcess.cs
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.TextManager.Interop;
+
+namespace Microsoft.CodeAnalysis.Testing.InProcess
+{
+ public class EditorInProcess : InProcComponent
+ {
+ internal static readonly Guid IWpfTextViewId = new Guid("8C40265E-9FDB-4F54-A0FD-EBB72B7D0476");
+
+ public EditorInProcess(TestServices testServices)
+ : base(testServices)
+ {
+ }
+
+ public async Task GetActiveTextViewAsync()
+ => (await GetActiveTextViewHostAsync()).TextView;
+
+ private async Task GetActiveVsTextViewAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var vsTextManager = await GetGlobalServiceAsync();
+
+ ErrorHandler.ThrowOnFailure(vsTextManager.GetActiveView(fMustHaveFocus: 1, pBuffer: null, ppView: out var vsTextView));
+
+ return vsTextView;
+ }
+
+ private async Task GetActiveTextViewHostAsync()
+ {
+ // The active text view might not have finished composing yet, waiting for the application to 'idle'
+ // means that it is done pumping messages (including WM_PAINT) and the window should return the correct text
+ // view.
+ await WaitForApplicationIdleAsync(CancellationToken.None);
+
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var activeVsTextView = (IVsUserData)await GetActiveVsTextViewAsync();
+
+ ErrorHandler.ThrowOnFailure(activeVsTextView.GetData(IWpfTextViewId, out var wpfTextViewHost));
+
+ return (IWpfTextViewHost)wpfTextViewHost;
+ }
+
+ public async Task SetTextAsync(string text)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var view = await GetActiveTextViewAsync();
+ var textSnapshot = view.TextSnapshot;
+ var replacementSpan = new SnapshotSpan(textSnapshot, 0, textSnapshot.Length);
+ view.TextBuffer.Replace(replacementSpan, text);
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/ErrorListExtensions.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/ErrorListExtensions.cs
new file mode 100644
index 0000000000..6477d9d2ec
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/ErrorListExtensions.cs
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Shell.TableManager;
+
+namespace Microsoft.CodeAnalysis.Testing.InProcess
+{
+ internal static class ErrorListExtensions
+ {
+ public static __VSERRORCATEGORY GetCategory(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrDefault(StandardTableKeyNames.ErrorSeverity, (__VSERRORCATEGORY)(-1));
+ }
+
+ public static string GetBuildTool(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrDefault(StandardTableKeyNames.BuildTool, "");
+ }
+
+ public static string? GetPath(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrDefault(StandardTableKeyNames.Path, null);
+ }
+
+ public static string? GetDocumentName(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrDefault(StandardTableKeyNames.DocumentName, null);
+ }
+
+ public static int? GetLine(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrNull(StandardTableKeyNames.Line);
+ }
+
+ public static int? GetColumn(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrNull(StandardTableKeyNames.Column);
+ }
+
+ public static string? GetErrorCode(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrDefault(StandardTableKeyNames.ErrorCode, null);
+ }
+
+ public static string? GetText(this ITableEntry tableEntry)
+ {
+ return tableEntry.GetValueOrDefault(StandardTableKeyNames.Text, null);
+ }
+
+ private static T GetValueOrDefault(this ITableEntry tableEntry, string keyName, T defaultValue)
+ {
+ if (!tableEntry.TryGetValue(keyName, out T value))
+ {
+ value = defaultValue;
+ }
+
+ return value;
+ }
+
+ private static T? GetValueOrNull(this ITableEntry tableEntry, string keyName)
+ where T : struct
+ {
+ if (!tableEntry.TryGetValue(keyName, out T value))
+ {
+ return null;
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/ErrorListInProcess.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/ErrorListInProcess.cs
new file mode 100644
index 0000000000..21fea7306b
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/ErrorListInProcess.cs
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Shell.TableControl;
+using Microsoft.VisualStudio.Shell.TableManager;
+using Task = System.Threading.Tasks.Task;
+
+namespace Microsoft.CodeAnalysis.Testing.InProcess
+{
+ public class ErrorListInProcess : InProcComponent
+ {
+ public ErrorListInProcess(TestServices testServices)
+ : base(testServices)
+ {
+ }
+
+ public async Task ShowBuildErrorsAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var errorList = await GetGlobalServiceAsync();
+ errorList.AreBuildErrorSourceEntriesShown = true;
+ errorList.AreOtherErrorSourceEntriesShown = false;
+ errorList.AreErrorsShown = true;
+ errorList.AreMessagesShown = true;
+ errorList.AreWarningsShown = false;
+ }
+
+ public async Task> GetBuildErrorsAsync(__VSERRORCATEGORY minimumSeverity = __VSERRORCATEGORY.EC_WARNING)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var errorItems = await GetErrorItemsAsync();
+ var list = new List();
+
+ foreach (var item in errorItems)
+ {
+ if (item.GetCategory() > minimumSeverity)
+ {
+ continue;
+ }
+
+ if (!item.TryGetValue(StandardTableKeyNames.ErrorSource, out var errorSource)
+ || (ErrorSource)errorSource != ErrorSource.Build)
+ {
+ continue;
+ }
+
+ var source = item.GetBuildTool();
+ var document = Path.GetFileName(item.GetPath() ?? item.GetDocumentName()) ?? "";
+ var line = item.GetLine() ?? -1;
+ var column = item.GetColumn() ?? -1;
+ var errorCode = item.GetErrorCode() ?? "";
+ var text = item.GetText() ?? "";
+ var severity = item.GetCategory() switch
+ {
+ __VSERRORCATEGORY.EC_ERROR => "error",
+ __VSERRORCATEGORY.EC_WARNING => "warning",
+ __VSERRORCATEGORY.EC_MESSAGE => "info",
+ var unknown => unknown.ToString(),
+ };
+
+ var message = $"({source}) {document}({line + 1}, {column + 1}): {severity} {errorCode}: {text}";
+ list.Add(message);
+ }
+
+ return list
+ .OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
+ .ThenBy(x => x, StringComparer.Ordinal)
+ .ToImmutableArray();
+ }
+
+ public async Task GetErrorCountAsync(__VSERRORCATEGORY minimumSeverity = __VSERRORCATEGORY.EC_WARNING)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var errorItems = await GetErrorItemsAsync();
+ return errorItems.Count(e => e.GetCategory() <= minimumSeverity);
+ }
+
+ private async Task> GetErrorItemsAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var errorList = await GetGlobalServiceAsync();
+ var args = await errorList.TableControl.ForceUpdateAsync();
+ return args.AllEntries.ToImmutableArray();
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/InProcComponent.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/InProcComponent.cs
new file mode 100644
index 0000000000..f489684626
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/InProcComponent.cs
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+using Microsoft.VisualStudio.ComponentModelHost;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Threading;
+using Task = System.Threading.Tasks.Task;
+
+namespace Microsoft.CodeAnalysis.Testing.InProcess
+{
+ public abstract class InProcComponent
+ {
+ protected InProcComponent(TestServices testServices)
+ {
+ TestServices = testServices ?? throw new ArgumentNullException(nameof(testServices));
+ }
+
+ public TestServices TestServices { get; }
+
+ protected JoinableTaskFactory JoinableTaskFactory => TestServices.JoinableTaskFactory;
+
+ protected async Task ExecuteCommandAsync(string commandName, string args = "")
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var dte = await GetGlobalServiceAsync();
+ dte.ExecuteCommand(commandName, args);
+ }
+
+ protected async Task GetGlobalServiceAsync()
+ where TService : class
+ where TInterface : class
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var serviceProvider = (IAsyncServiceProvider2)await AsyncServiceProvider.GlobalProvider.GetServiceAsync(typeof(SAsyncServiceProvider));
+ Assumes.Present(serviceProvider);
+ return (TInterface)await serviceProvider.GetServiceAsync(typeof(TService));
+ }
+
+ protected async Task GetComponentModelServiceAsync()
+ where TService : class
+ {
+ var componentModel = await GetGlobalServiceAsync();
+ return componentModel.GetService();
+ }
+
+ ///
+ /// Waiting for the application to 'idle' means that it is done pumping messages (including WM_PAINT).
+ ///
+ /// The cancellation token that the operation will observe.
+ /// A representing the asynchronous operation.
+ protected static async Task WaitForApplicationIdleAsync(CancellationToken cancellationToken)
+ {
+ var synchronizationContext = new DispatcherSynchronizationContext(Application.Current.Dispatcher, DispatcherPriority.ApplicationIdle);
+ var taskScheduler = new SynchronizationContextTaskScheduler(synchronizationContext);
+ await Task.Factory.StartNew(
+ () => { },
+ cancellationToken,
+ TaskCreationOptions.None,
+ taskScheduler);
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/SolutionExplorerInProcess.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/SolutionExplorerInProcess.cs
new file mode 100644
index 0000000000..4bbcf6c0ab
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/SolutionExplorerInProcess.cs
@@ -0,0 +1,578 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.OperationProgress;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.TextManager.Interop;
+using Microsoft.VisualStudio.Threading;
+using NuGet.SolutionRestoreManager;
+using Task = System.Threading.Tasks.Task;
+
+namespace Microsoft.CodeAnalysis.Testing.InProcess
+{
+ public class SolutionExplorerInProcess : InProcComponent
+ {
+ public SolutionExplorerInProcess(TestServices testServices)
+ : base(testServices)
+ {
+ }
+
+ private async Task IsSolutionOpenAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var solution = await GetGlobalServiceAsync();
+ ErrorHandler.ThrowOnFailure(solution.GetProperty((int)__VSPROPID.VSPROPID_IsSolutionOpen, out var isOpen));
+ return (bool)isOpen;
+ }
+
+ public async Task CloseSolutionAsync(bool saveFirst = false)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+ if (!await IsSolutionOpenAsync())
+ {
+ return;
+ }
+
+ if (saveFirst)
+ {
+ await SaveSolutionAsync();
+ }
+
+ await CloseSolutionAsync();
+ }
+
+ private async Task CloseSolutionAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var solution = await GetGlobalServiceAsync();
+ if (!await IsSolutionOpenAsync())
+ {
+ return;
+ }
+
+ using var semaphore = new SemaphoreSlim(1);
+ using var solutionEvents = new SolutionEvents(JoinableTaskFactory, solution);
+
+ await semaphore.WaitAsync();
+
+ void HandleAfterCloseSolution(object sender, EventArgs e) => semaphore.Release();
+
+ solutionEvents.AfterCloseSolution += HandleAfterCloseSolution;
+ try
+ {
+ ErrorHandler.ThrowOnFailure(solution.CloseSolutionElement((uint)__VSSLNCLOSEOPTIONS.SLNCLOSEOPT_DeleteProject | (uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave, null, 0));
+ await semaphore.WaitAsync();
+ }
+ finally
+ {
+ solutionEvents.AfterCloseSolution -= HandleAfterCloseSolution;
+ }
+ }
+
+ public async Task CreateSolutionAsync(string solutionName)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var solutionPath = CreateTemporaryPath();
+ await CreateSolutionAsync(solutionPath, solutionName);
+ }
+
+ private async Task CreateSolutionAsync(string solutionPath, string solutionName)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ await CloseSolutionAsync();
+
+ var solutionFileName = Path.ChangeExtension(solutionName, ".sln");
+ Directory.CreateDirectory(solutionPath);
+
+ var solution = await GetGlobalServiceAsync();
+ ErrorHandler.ThrowOnFailure(solution.CreateSolution(solutionPath, solutionFileName, (uint)__VSCREATESOLUTIONFLAGS.CSF_SILENT));
+ ErrorHandler.ThrowOnFailure(solution.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0));
+ }
+
+ public async Task SaveSolutionAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ if (!await IsSolutionOpenAsync())
+ {
+ throw new InvalidOperationException("Cannot save solution when no solution is open.");
+ }
+
+ var solution = await GetGlobalServiceAsync();
+
+ // Make sure the directory exists so the Save dialog doesn't appear
+ ErrorHandler.ThrowOnFailure(solution.GetSolutionInfo(out var solutionDirectory, out _, out _));
+ Directory.CreateDirectory(solutionDirectory);
+
+ ErrorHandler.ThrowOnFailure(solution.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0));
+ }
+
+ private static string ConvertLanguageName(string languageName)
+ {
+ return languageName switch
+ {
+ LanguageNames.CSharp => "CSharp",
+ LanguageNames.VisualBasic => "VisualBasic",
+ _ => throw new ArgumentException($"'{languageName}' is not supported.", nameof(languageName)),
+ };
+ }
+
+ private async Task GetDirectoryNameAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var dte = await GetGlobalServiceAsync();
+ var solution = (EnvDTE80.Solution2)dte.Solution;
+ var solutionFullName = solution.FullName;
+ var solutionFileFullPath = string.IsNullOrEmpty(solutionFullName)
+ ? throw new InvalidOperationException()
+ : solutionFullName;
+
+ return Path.GetDirectoryName(solutionFileFullPath);
+ }
+
+ private async Task> GetCSharpProjectTemplatesAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var dte = await GetGlobalServiceAsync();
+ var localeID = dte.LocaleID;
+
+ var builder = ImmutableDictionary.CreateBuilder();
+ builder[WellKnownProjectTemplates.ClassLibrary] = $@"Windows\{localeID}\ClassLibrary.zip";
+ builder[WellKnownProjectTemplates.ConsoleApplication] = "Microsoft.CSharp.ConsoleApplication";
+ builder[WellKnownProjectTemplates.Website] = "EmptyWeb.zip";
+ builder[WellKnownProjectTemplates.WinFormsApplication] = "WindowsApplication.zip";
+ builder[WellKnownProjectTemplates.WpfApplication] = "WpfApplication.zip";
+ builder[WellKnownProjectTemplates.WebApplication] = "WebApplicationProject40";
+ return builder.ToImmutable();
+ }
+
+ private async Task> GetVisualBasicProjectTemplatesAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var dte = await GetGlobalServiceAsync();
+ var localeID = dte.LocaleID;
+
+ var builder = ImmutableDictionary.CreateBuilder();
+ builder[WellKnownProjectTemplates.ClassLibrary] = $@"Windows\{localeID}\ClassLibrary.zip";
+ builder[WellKnownProjectTemplates.ConsoleApplication] = "Microsoft.VisualBasic.Windows.ConsoleApplication";
+ builder[WellKnownProjectTemplates.Website] = "EmptyWeb.zip";
+ builder[WellKnownProjectTemplates.WinFormsApplication] = "WindowsApplication.zip";
+ builder[WellKnownProjectTemplates.WpfApplication] = "WpfApplication.zip";
+ builder[WellKnownProjectTemplates.WebApplication] = "WebApplicationProject40";
+ return builder.ToImmutable();
+ }
+
+ public async Task AddProjectAsync(string projectName, string projectTemplate, string languageName)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var projectPath = Path.Combine(await GetDirectoryNameAsync(), projectName);
+ var projectTemplatePath = await GetProjectTemplatePathAsync(projectTemplate, ConvertLanguageName(languageName));
+ var solution = await GetGlobalServiceAsync();
+ ErrorHandler.ThrowOnFailure(solution.AddNewProjectFromTemplate(projectTemplatePath, null, null, projectPath, projectName, null, out _));
+ }
+
+ private async Task GetProjectTemplatePathAsync(string projectTemplate, string languageName)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var dte = await GetGlobalServiceAsync();
+ var solution = (EnvDTE80.Solution2)dte.Solution;
+
+ if (string.Equals(languageName, "csharp", StringComparison.OrdinalIgnoreCase)
+ && (await GetCSharpProjectTemplatesAsync()).TryGetValue(projectTemplate, out var csharpProjectTemplate))
+ {
+ return solution.GetProjectTemplate(csharpProjectTemplate, languageName);
+ }
+
+ if (string.Equals(languageName, "visualbasic", StringComparison.OrdinalIgnoreCase)
+ && (await GetVisualBasicProjectTemplatesAsync()).TryGetValue(projectTemplate, out var visualBasicProjectTemplate))
+ {
+ return solution.GetProjectTemplate(visualBasicProjectTemplate, languageName);
+ }
+
+ return solution.GetProjectTemplate(projectTemplate, languageName);
+ }
+
+ public async Task RestoreNuGetPackagesAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var dte = await GetGlobalServiceAsync();
+ var solution = (EnvDTE80.Solution2)dte.Solution;
+ foreach (var project in solution.Projects.OfType())
+ {
+ await RestoreNuGetPackagesAsync(project.FullName, cancellationToken);
+ }
+ }
+
+ public async Task RestoreNuGetPackagesAsync(string projectName, CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var operationProgressStatus = await GetGlobalServiceAsync();
+ var stageStatus = operationProgressStatus.GetStageStatus(CommonOperationProgressStageIds.Intellisense);
+ await stageStatus.WaitForCompletionAsync();
+
+ var solutionRestoreService = await GetComponentModelServiceAsync();
+ await solutionRestoreService.CurrentRestoreOperation;
+
+ var projectFullPath = (await GetProjectAsync(projectName)).FullName;
+ var solutionRestoreStatusProvider = await GetComponentModelServiceAsync();
+ if (await solutionRestoreStatusProvider.IsRestoreCompleteAsync(cancellationToken))
+ {
+ return;
+ }
+
+ var solutionRestoreService2 = (IVsSolutionRestoreService2)solutionRestoreService;
+ await solutionRestoreService2.NominateProjectAsync(projectFullPath, cancellationToken);
+
+ while (true)
+ {
+ if (await solutionRestoreStatusProvider.IsRestoreCompleteAsync(cancellationToken))
+ {
+ return;
+ }
+
+ await Task.Delay(TimeSpan.FromMilliseconds(50), cancellationToken);
+ }
+ }
+
+ public async Task BuildSolutionAsync(bool waitForBuildToFinish)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var buildOutputWindowPane = await GetBuildOutputWindowPaneAsync();
+ buildOutputWindowPane.Clear();
+
+ await ExecuteCommandAsync(WellKnownCommandNames.Build.BuildSolution);
+ if (waitForBuildToFinish)
+ {
+ return await WaitForBuildToFinishAsync(buildOutputWindowPane);
+ }
+
+ return null;
+ }
+
+ public async Task WaitForBuildToFinishAsync()
+ {
+ var buildOutputWindowPane = await GetBuildOutputWindowPaneAsync();
+ return await WaitForBuildToFinishAsync(buildOutputWindowPane);
+ }
+
+ public async Task GetBuildOutputWindowPaneAsync()
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var outputWindow = await GetGlobalServiceAsync();
+ ErrorHandler.ThrowOnFailure(outputWindow.GetPane(VSConstants.OutputWindowPaneGuid.BuildOutputPane_guid, out var pane));
+ return pane;
+ }
+
+ private async Task WaitForBuildToFinishAsync(IVsOutputWindowPane buildOutputWindowPane)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var buildManager = await GetGlobalServiceAsync();
+ using var semaphore = new SemaphoreSlim(1);
+ using var solutionEvents = new UpdateSolutionEvents(buildManager);
+
+ await semaphore.WaitAsync();
+
+ void HandleUpdateSolutionDone(bool succeeded, bool modified, bool canceled) => semaphore.Release();
+ solutionEvents.OnUpdateSolutionDone += HandleUpdateSolutionDone;
+ try
+ {
+ await semaphore.WaitAsync();
+ }
+ finally
+ {
+ solutionEvents.OnUpdateSolutionDone -= HandleUpdateSolutionDone;
+ }
+
+ // Force the error list to update
+ ErrorHandler.ThrowOnFailure(buildOutputWindowPane.FlushToTaskList());
+
+ var textView = (IVsTextView)buildOutputWindowPane;
+ ErrorHandler.ThrowOnFailure(((IVsUserData)textView).GetData(EditorInProcess.IWpfTextViewId, out var wpfTextViewHost));
+ var lines = ((IWpfTextViewHost)wpfTextViewHost).TextView.TextViewLines;
+ if (lines.Count < 1)
+ {
+ return string.Empty;
+ }
+
+ return lines[lines.Count - 2].Extent.GetText();
+ }
+
+ private string CreateTemporaryPath()
+ {
+ return Path.Combine(Path.GetTempPath(), "roslyn-sdk-test", Path.GetRandomFileName());
+ }
+
+ private async Task GetProjectAsync(string nameOrFileName)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var dte = await GetGlobalServiceAsync();
+ var solution = (EnvDTE80.Solution2)dte.Solution;
+ return solution.Projects.OfType().First(
+ project =>
+ {
+ ThreadHelper.ThrowIfNotOnUIThread();
+ return string.Equals(project.FileName, nameOrFileName, StringComparison.OrdinalIgnoreCase)
+ || string.Equals(project.Name, nameOrFileName, StringComparison.OrdinalIgnoreCase);
+ });
+ }
+
+ private sealed class SolutionEvents : IVsSolutionEvents, IDisposable
+ {
+ private readonly JoinableTaskFactory _joinableTaskFactory;
+ private readonly IVsSolution _solution;
+ private readonly uint _cookie;
+
+ public SolutionEvents(JoinableTaskFactory joinableTaskFactory, IVsSolution solution)
+ {
+ ThreadHelper.ThrowIfNotOnUIThread();
+
+ _joinableTaskFactory = joinableTaskFactory;
+ _solution = solution;
+ ErrorHandler.ThrowOnFailure(solution.AdviseSolutionEvents(this, out _cookie));
+ }
+
+ public event EventHandler? AfterCloseSolution;
+
+ public void Dispose()
+ {
+ _joinableTaskFactory.Run(async () =>
+ {
+ await _joinableTaskFactory.SwitchToMainThreadAsync();
+ ErrorHandler.ThrowOnFailure(_solution.UnadviseSolutionEvents(_cookie));
+ });
+ }
+
+ public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnQueryCloseSolution(object pUnkReserved, ref int pfCancel)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnBeforeCloseSolution(object pUnkReserved)
+ {
+ return VSConstants.S_OK;
+ }
+
+ public int OnAfterCloseSolution(object pUnkReserved)
+ {
+ AfterCloseSolution?.Invoke(this, EventArgs.Empty);
+ return VSConstants.S_OK;
+ }
+ }
+
+ internal sealed class UpdateSolutionEvents : IVsUpdateSolutionEvents, IVsUpdateSolutionEvents2, IDisposable
+ {
+ private uint _cookie;
+ private IVsSolutionBuildManager2 _solutionBuildManager;
+
+ internal delegate void UpdateSolutionDoneEvent(bool succeeded, bool modified, bool canceled);
+
+ internal delegate void UpdateSolutionBeginEvent(ref bool cancel);
+
+ internal delegate void UpdateSolutionStartUpdateEvent(ref bool cancel);
+
+ internal delegate void UpdateProjectConfigDoneEvent(IVsHierarchy projectHierarchy, IVsCfg projectConfig, int success);
+
+ internal delegate void UpdateProjectConfigBeginEvent(IVsHierarchy projectHierarchy, IVsCfg projectConfig);
+
+ public event UpdateSolutionDoneEvent? OnUpdateSolutionDone;
+
+ public event UpdateSolutionBeginEvent? OnUpdateSolutionBegin;
+
+ public event UpdateSolutionStartUpdateEvent? OnUpdateSolutionStartUpdate;
+
+ public event Action? OnActiveProjectConfigurationChange;
+
+ public event Action? OnUpdateSolutionCancel;
+
+ public event UpdateProjectConfigDoneEvent? OnUpdateProjectConfigDone;
+
+ public event UpdateProjectConfigBeginEvent? OnUpdateProjectConfigBegin;
+
+ internal UpdateSolutionEvents(IVsSolutionBuildManager2 solutionBuildManager)
+ {
+ ThreadHelper.ThrowIfNotOnUIThread();
+
+ _solutionBuildManager = solutionBuildManager;
+ ErrorHandler.ThrowOnFailure(solutionBuildManager.AdviseUpdateSolutionEvents(this, out _cookie));
+ }
+
+ int IVsUpdateSolutionEvents.UpdateSolution_Begin(ref int pfCancelUpdate)
+ {
+ var cancel = false;
+ OnUpdateSolutionBegin?.Invoke(ref cancel);
+ if (cancel)
+ {
+ pfCancelUpdate = 1;
+ }
+
+ return 0;
+ }
+
+ int IVsUpdateSolutionEvents.UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand)
+ {
+ OnUpdateSolutionDone?.Invoke(fSucceeded != 0, fModified != 0, fCancelCommand != 0);
+ return 0;
+ }
+
+ int IVsUpdateSolutionEvents.UpdateSolution_StartUpdate(ref int pfCancelUpdate)
+ {
+ return UpdateSolution_StartUpdate(ref pfCancelUpdate);
+ }
+
+ int IVsUpdateSolutionEvents.UpdateSolution_Cancel()
+ {
+ OnUpdateSolutionCancel?.Invoke();
+ return 0;
+ }
+
+ int IVsUpdateSolutionEvents.OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy)
+ {
+ return OnActiveProjectCfgChange(pIVsHierarchy);
+ }
+
+ int IVsUpdateSolutionEvents2.UpdateSolution_Begin(ref int pfCancelUpdate)
+ {
+ var cancel = false;
+ OnUpdateSolutionBegin?.Invoke(ref cancel);
+ if (cancel)
+ {
+ pfCancelUpdate = 1;
+ }
+
+ return 0;
+ }
+
+ int IVsUpdateSolutionEvents2.UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand)
+ {
+ OnUpdateSolutionDone?.Invoke(fSucceeded != 0, fModified != 0, fCancelCommand != 0);
+ return 0;
+ }
+
+ int IVsUpdateSolutionEvents2.UpdateSolution_StartUpdate(ref int pfCancelUpdate)
+ {
+ return UpdateSolution_StartUpdate(ref pfCancelUpdate);
+ }
+
+ int IVsUpdateSolutionEvents2.UpdateSolution_Cancel()
+ {
+ OnUpdateSolutionCancel?.Invoke();
+ return 0;
+ }
+
+ int IVsUpdateSolutionEvents2.OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy)
+ {
+ return OnActiveProjectCfgChange(pIVsHierarchy);
+ }
+
+ int IVsUpdateSolutionEvents2.UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel)
+ {
+ OnUpdateProjectConfigBegin?.Invoke(pHierProj, pCfgProj);
+ return 0;
+ }
+
+ int IVsUpdateSolutionEvents2.UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel)
+ {
+ OnUpdateProjectConfigDone?.Invoke(pHierProj, pCfgProj, fSuccess);
+ return 0;
+ }
+
+ private int UpdateSolution_StartUpdate(ref int pfCancelUpdate)
+ {
+ var cancel = false;
+ OnUpdateSolutionStartUpdate?.Invoke(ref cancel);
+ if (cancel)
+ {
+ pfCancelUpdate = 1;
+ }
+
+ return 0;
+ }
+
+ private int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy)
+ {
+ OnActiveProjectConfigurationChange?.Invoke();
+ return 0;
+ }
+
+ void IDisposable.Dispose()
+ {
+ ThreadHelper.ThrowIfNotOnUIThread();
+
+ OnUpdateSolutionDone = null;
+ OnUpdateSolutionBegin = null;
+ OnUpdateSolutionStartUpdate = null;
+ OnActiveProjectConfigurationChange = null;
+ OnUpdateSolutionCancel = null;
+ OnUpdateProjectConfigDone = null;
+ OnUpdateProjectConfigBegin = null;
+
+ if (_cookie != 0)
+ {
+ var tempCookie = _cookie;
+ _cookie = 0;
+ ErrorHandler.ThrowOnFailure(_solutionBuildManager.UnadviseUpdateSolutionEvents(tempCookie));
+ }
+ }
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/SynchronizationContextTaskScheduler.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/SynchronizationContextTaskScheduler.cs
new file mode 100644
index 0000000000..95f99b12a0
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/SynchronizationContextTaskScheduler.cs
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.CodeAnalysis.Testing.InProcess
+{
+ // Based on CoreCLR's implementation of the TaskScheduler they return from TaskScheduler.FromCurrentSynchronizationContext
+ internal class SynchronizationContextTaskScheduler : TaskScheduler
+ {
+ private readonly SendOrPostCallback _postCallback;
+ private readonly SynchronizationContext _synchronizationContext;
+
+ internal SynchronizationContextTaskScheduler(SynchronizationContext synchronizationContext)
+ {
+ _postCallback = new SendOrPostCallback(PostCallback);
+ _synchronizationContext = synchronizationContext ?? throw new ArgumentNullException(nameof(synchronizationContext));
+ }
+
+ public override int MaximumConcurrencyLevel => 1;
+
+ protected override void QueueTask(Task task)
+ {
+#pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs
+ _synchronizationContext.Post(_postCallback, task);
+#pragma warning restore VSTHRD001 // Avoid legacy thread switching APIs
+ }
+
+ protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
+ {
+ if (SynchronizationContext.Current == _synchronizationContext)
+ {
+ return TryExecuteTask(task);
+ }
+
+ return false;
+ }
+
+ protected override IEnumerable? GetScheduledTasks()
+ => null;
+
+ private void PostCallback(object obj)
+ => TryExecuteTask((Task)obj);
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/TestServices.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/TestServices.cs
new file mode 100644
index 0000000000..160a3e779e
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/InProcess/TestServices.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Threading;
+
+namespace Microsoft.CodeAnalysis.Testing.InProcess
+{
+ public class TestServices
+ {
+ protected TestServices(JoinableTaskFactory joinableTaskFactory)
+ {
+ JoinableTaskFactory = joinableTaskFactory;
+
+ Editor = new EditorInProcess(this);
+ ErrorList = new ErrorListInProcess(this);
+ SolutionExplorer = new SolutionExplorerInProcess(this);
+ }
+
+ public JoinableTaskFactory JoinableTaskFactory { get; }
+
+ public EditorInProcess Editor { get; }
+
+ public ErrorListInProcess ErrorList { get; }
+
+ public SolutionExplorerInProcess SolutionExplorer { get; }
+
+ internal static async Task CreateAsync(JoinableTaskFactory joinableTaskFactory)
+ {
+ var services = new TestServices(joinableTaskFactory);
+ await services.InitializeAsync();
+ return services;
+ }
+
+ protected virtual Task InitializeAsync()
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/Roslyn.SDK.IntegrationTests.csproj b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/Roslyn.SDK.IntegrationTests.csproj
new file mode 100644
index 0000000000..d8d0265eb4
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/Roslyn.SDK.IntegrationTests.csproj
@@ -0,0 +1,45 @@
+
+
+
+ net472
+ true
+
+ Microsoft.CodeAnalysis.Testing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/WellKnownCommandNames.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/WellKnownCommandNames.cs
new file mode 100644
index 0000000000..3c162a8d4a
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/WellKnownCommandNames.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.CodeAnalysis.Testing
+{
+ internal static class WellKnownCommandNames
+ {
+ public static class Build
+ {
+ public const string BuildSolution = "Build.BuildSolution";
+ }
+ }
+}
diff --git a/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/WellKnownProjectTemplates.cs b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/WellKnownProjectTemplates.cs
new file mode 100644
index 0000000000..504eb8d6e5
--- /dev/null
+++ b/tests/VisualStudio.Roslyn.SDK/Roslyn.SDK.IntegrationTests/WellKnownProjectTemplates.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.CodeAnalysis.Testing
+{
+ internal static class WellKnownProjectTemplates
+ {
+ public const string ClassLibrary = nameof(ClassLibrary);
+ public const string ConsoleApplication = nameof(ConsoleApplication);
+ public const string Website = nameof(Website);
+ public const string WinFormsApplication = nameof(WinFormsApplication);
+ public const string WpfApplication = nameof(WpfApplication);
+ public const string WebApplication = nameof(WebApplication);
+ public const string CSharpNetCoreClassLibrary = "Microsoft.CSharp.NETCore.ClassLibrary";
+ public const string VisualBasicNetCoreClassLibrary = "Microsoft.VisualBasic.NETCore.ClassLibrary";
+ public const string CSharpNetCoreConsoleApplication = "Microsoft.CSharp.NETCore.ConsoleApplication";
+ public const string VisualBasicNetCoreConsoleApplication = "Microsoft.VisualBasic.NETCore.ConsoleApplication";
+ public const string CSharpNetCoreUnitTest = "Microsoft.CSharp.NETCore.UnitTest";
+ public const string CSharpNetCoreXUnitTest = "Microsoft.CSharp.NETCore.XUnitTest";
+ }
+}