提交 3379fcb5 编写于 作者: C CyrusNajmabadi

Merge pull request #11023 from CyrusNajmabadi/usingOptions

Add options to enable/disable nuget search.
......@@ -9,14 +9,17 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.CodeFixes.AddImport;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.SymbolSearch;
using Moq;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.AddUsing
{
using FixProviderData = Tuple<IPackageInstallerService, IPackageSearchService>;
using FixProviderData = Tuple<IPackageInstallerService, ISymbolSearchService>;
public partial class AddUsingTests
{
......@@ -27,6 +30,15 @@ public class NuGet : AddUsingTests
private static readonly ImmutableArray<PackageSource> NugetPackageSources =
ImmutableArray.Create(new PackageSource(NugetOrgSource, "http://nuget.org/"));
protected override async Task<TestWorkspace> CreateWorkspaceFromFileAsync(string definition, ParseOptions parseOptions, CompilationOptions compilationOptions)
{
var workspace = await base.CreateWorkspaceFromFileAsync(definition, parseOptions, compilationOptions);
workspace.Options = workspace.Options
.WithChangedOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp, true)
.WithChangedOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp, true);
return workspace;
}
internal override Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(
Workspace workspace, object fixProviderData)
{
......@@ -50,7 +62,7 @@ public async Task TestSearchPackageSingleName()
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
var packageServiceMock = new Mock<IPackageSearchService>();
var packageServiceMock = new Mock<ISymbolSearchService>();
packageServiceMock.Setup(s => s.FindPackagesWithType(
NugetOrgSource, "NuGetType", 0, It.IsAny<CancellationToken>()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")));
......@@ -79,7 +91,7 @@ public async Task TestSearchPackageMultipleNames()
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
var packageServiceMock = new Mock<IPackageSearchService>();
var packageServiceMock = new Mock<ISymbolSearchService>();
packageServiceMock.Setup(s => s.FindPackagesWithType(
NugetOrgSource, "NuGetType", 0, It.IsAny<CancellationToken>()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")));
......@@ -110,7 +122,7 @@ public async Task TestMissingIfPackageAlreadyInstalled()
installerServiceMock.Setup(s => s.IsInstalled(It.IsAny<Workspace>(), It.IsAny<ProjectId>(), "NuGetPackage"))
.Returns(true);
var packageServiceMock = new Mock<IPackageSearchService>();
var packageServiceMock = new Mock<ISymbolSearchService>();
packageServiceMock.Setup(s => s.FindPackagesWithType(
NugetOrgSource, "NuGetType", 0, It.IsAny<CancellationToken>()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")));
......@@ -134,7 +146,7 @@ public async Task TestOptionsOffered()
installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage"))
.Returns(new[] { "1.0", "2.0" });
var packageServiceMock = new Mock<IPackageSearchService>();
var packageServiceMock = new Mock<ISymbolSearchService>();
packageServiceMock.Setup(s => s.FindPackagesWithType(
NugetOrgSource, "NuGetType", 0, It.IsAny<CancellationToken>()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")));
......@@ -180,7 +192,7 @@ public async Task TestInstallGetsCalledNoVersion()
installerServiceMock.Setup(s => s.TryInstallPackage(
It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", /*versionOpt*/ null, It.IsAny<CancellationToken>()));
var packageServiceMock = new Mock<IPackageSearchService>();
var packageServiceMock = new Mock<ISymbolSearchService>();
packageServiceMock.Setup(s => s.FindPackagesWithType(
NugetOrgSource, "NuGetType", 0, It.IsAny<CancellationToken>()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")));
......@@ -212,7 +224,7 @@ public async Task TestInstallGetsCalledWithVersion()
installerServiceMock.Setup(s => s.TryInstallPackage(
It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", "1.0", It.IsAny<CancellationToken>()));
var packageServiceMock = new Mock<IPackageSearchService>();
var packageServiceMock = new Mock<ISymbolSearchService>();
packageServiceMock.Setup(s => s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny<CancellationToken>()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")));
......
......@@ -5,11 +5,14 @@ Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Packaging
Imports Microsoft.CodeAnalysis.Shared.Options
Imports Microsoft.CodeAnalysis.SymbolSearch
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
Imports Moq
Imports ProviderData = System.Tuple(Of Microsoft.CodeAnalysis.Packaging.IPackageInstallerService, Microsoft.CodeAnalysis.Packaging.IPackageSearchService)
Imports ProviderData = System.Tuple(Of Microsoft.CodeAnalysis.Packaging.IPackageInstallerService, Microsoft.CodeAnalysis.SymbolSearch.ISymbolSearchService)
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImport
Partial Public Class AddImportTests
......@@ -21,6 +24,14 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp
Private Shared ReadOnly NugetPackageSources As ImmutableArray(Of PackageSource) =
ImmutableArray.Create(New PackageSource(NugetOrgSource, "http://nuget.org"))
Protected Overrides Async Function CreateWorkspaceFromFileAsync(definition As String, parseOptions As ParseOptions, compilationOptions As CompilationOptions) As Task(Of TestWorkspace)
Dim workspace = Await MyBase.CreateWorkspaceFromFileAsync(definition, parseOptions, compilationOptions)
workspace.Options = workspace.Options.
WithChangedOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic, True).
WithChangedOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic, True)
Return workspace
End Function
Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace, fixProviderData As Object) As Tuple(Of DiagnosticAnalyzer, CodeFixProvider)
Dim data = DirectCast(fixProviderData, ProviderData)
Return Tuple.Create(Of DiagnosticAnalyzer, CodeFixProvider)(
......@@ -40,7 +51,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
Dim packageServiceMock = New Mock(Of IPackageSearchService)()
Dim packageServiceMock = New Mock(Of ISymbolSearchService)()
packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")))
......@@ -65,7 +76,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
Dim packageServiceMock = New Mock(Of IPackageSearchService)()
Dim packageServiceMock = New Mock(Of ISymbolSearchService)()
packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")))
......@@ -92,7 +103,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
installerServiceMock.Setup(Function(s) s.IsInstalled(It.IsAny(Of Workspace)(), It.IsAny(Of ProjectId)(), "NuGetPackage")).
Returns(True)
Dim packageServiceMock = New Mock(Of IPackageSearchService)()
Dim packageServiceMock = New Mock(Of ISymbolSearchService)()
packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")))
......@@ -114,7 +125,7 @@ fixProviderData:=New ProviderData(installerServiceMock.Object, packageServiceMoc
installerServiceMock.Setup(Function(s) s.GetInstalledVersions("NuGetPackage")).
Returns({"1.0", "2.0"})
Dim packageServiceMock = New Mock(Of IPackageSearchService)()
Dim packageServiceMock = New Mock(Of ISymbolSearchService)()
packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")))
......@@ -155,7 +166,7 @@ fixProviderData:=data)
installerServiceMock.Setup(Function(s) s.TryInstallPackage(
It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", Nothing, It.IsAny(Of CancellationToken)))
Dim packageServiceMock = New Mock(Of IPackageSearchService)()
Dim packageServiceMock = New Mock(Of ISymbolSearchService)()
packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")))
......@@ -183,7 +194,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
installerServiceMock.Setup(Function(s) s.TryInstallPackage(
It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", "1.0", It.IsAny(Of CancellationToken)))
Dim packageServiceMock = New Mock(Of IPackageSearchService)()
Dim packageServiceMock = New Mock(Of ISymbolSearchService)()
packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")))
......
......@@ -19,6 +19,7 @@
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.SymbolSearch;
using Roslyn.Utilities;
using static Microsoft.CodeAnalysis.CSharp.CodeFixes.AddImport.AddImportDiagnosticIds;
......@@ -154,8 +155,8 @@ public CSharpAddImportCodeFixProvider()
/// <summary>For testing purposes only (so that tests can pass in mock values)</summary>
internal CSharpAddImportCodeFixProvider(
IPackageInstallerService installerService,
IPackageSearchService packageSearchService)
: base(installerService, packageSearchService)
ISymbolSearchService symbolSearchService)
: base(installerService, symbolSearchService)
{
}
......
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.SymbolSearch;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeFixes.AddImport
......
// 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 System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
......@@ -9,6 +8,8 @@
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.SymbolSearch;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeFixes.AddImport
......@@ -232,32 +233,41 @@ private async Task<IList<SymbolReference>> GetMatchingTypesAsync(SearchScope sea
{
var workspaceServices = _document.Project.Solution.Workspace.Services;
var packageSearchService = _owner._packageSearchService ?? workspaceServices.GetService<IPackageSearchService>();
var referenceAssemblySearchService = _owner._referenceAssemblySearchService ?? workspaceServices.GetService<IReferenceAssemblySearchService>();
var symbolSearchService = _owner._symbolSearchService ?? workspaceServices.GetService<ISymbolSearchService>();
var installerService = _owner._packageInstallerService ?? workspaceServices.GetService<IPackageInstallerService>();
if (referenceAssemblySearchService != null)
var language = _document.Project.Language;
var options = workspaceServices.Workspace.Options;
var searchReferenceAssemblies = options.GetOption(
AddImportOptions.SuggestForTypesInReferenceAssemblies, language);
var searchNugetPackages = options.GetOption(
AddImportOptions.SuggestForTypesInNuGetPackages, language);
if (symbolSearchService != null &&
searchReferenceAssemblies)
{
cancellationToken.ThrowIfCancellationRequested();
await FindReferenceAssemblyTypeReferencesAsync(
referenceAssemblySearchService, allReferences, nameNode, name, arity, isAttributeSearch, cancellationToken).ConfigureAwait(false);
symbolSearchService, allReferences, nameNode, name, arity, isAttributeSearch, cancellationToken).ConfigureAwait(false);
}
if (packageSearchService != null &&
if (symbolSearchService != null &&
searchNugetPackages &&
installerService.IsEnabled)
{
foreach (var packageSource in installerService.PackageSources)
{
cancellationToken.ThrowIfCancellationRequested();
await FindNugetTypeReferencesAsync(
packageSource, packageSearchService, installerService, allReferences,
packageSource, symbolSearchService, installerService, allReferences,
nameNode, name, arity, isAttributeSearch, cancellationToken).ConfigureAwait(false);
}
}
}
private async Task FindReferenceAssemblyTypeReferencesAsync(
IReferenceAssemblySearchService searchService,
ISymbolSearchService searchService,
List<Reference> allReferences,
TSimpleNameSyntax nameNode,
string name,
......@@ -283,7 +293,7 @@ private async Task<IList<SymbolReference>> GetMatchingTypesAsync(SearchScope sea
private async Task FindNugetTypeReferencesAsync(
PackageSource source,
IPackageSearchService searchService,
ISymbolSearchService searchService,
IPackageInstallerService installerService,
List<Reference> allReferences,
TSimpleNameSyntax nameNode,
......
......@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.SymbolSearch;
using Roslyn.Utilities;
using static Roslyn.Utilities.PortableShim;
......@@ -25,18 +26,15 @@ internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSynt
private const int MaxResults = 3;
private readonly IPackageInstallerService _packageInstallerService;
private readonly IPackageSearchService _packageSearchService;
private readonly IReferenceAssemblySearchService _referenceAssemblySearchService;
private readonly ISymbolSearchService _symbolSearchService;
/// <summary>Values for these parameters can be provided (during testing) for mocking purposes.</summary>
protected AbstractAddImportCodeFixProvider(
IPackageInstallerService packageInstallerService = null,
IPackageSearchService packageSearchService = null,
IReferenceAssemblySearchService referenceAssemblySearchService = null)
ISymbolSearchService symbolSearchService = null)
{
_packageInstallerService = packageInstallerService;
_packageSearchService = packageSearchService;
_referenceAssemblySearchService = referenceAssemblySearchService;
_symbolSearchService = symbolSearchService;
}
protected abstract bool CanAddImport(SyntaxNode node, CancellationToken cancellationToken);
......@@ -81,7 +79,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
return;
}
var placeSystemNamespaceFirst = document.Project.Solution.Workspace.Options.GetOption(
var options = document.Project.Solution.Workspace.Options;
var placeSystemNamespaceFirst = options.GetOption(
OrganizerOptions.PlaceSystemNamespaceFirst, document.Project.Language);
using (Logger.LogBlock(FunctionId.Refactoring_AddImport, cancellationToken))
......
......@@ -295,8 +295,9 @@
<Compile Include="RemoveUnnecessaryImports\AbstractRemoveUnnecessaryImportsService.cs" />
<Compile Include="ReplaceMethodWithProperty\ReplaceMethodWithPropertyCodeRefactoringProvider.cs" />
<Compile Include="ReplaceMethodWithProperty\IReplaceMethodWithPropertyService.cs" />
<Compile Include="Shared\Options\AddImportOptionsProvider.cs" />
<Compile Include="Shared\Extensions\ProjectExtensions.cs" />
<Compile Include="Shared\Options\OrganizerOptionsProvider.cs" />
<Compile Include="Shared\Options\AddImportOptions.cs" />
<Compile Include="Shared\Options\RuntimeOptions.cs" />
<Compile Include="Shared\Options\RuntimeOptionsProvider.cs" />
<Compile Include="Shared\Options\ServiceComponentOnOffOptionsProvider.cs" />
......
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Shared.Options
{
internal class AddImportOptions
{
public const string FeatureName = "AddImport";
public static PerLanguageOption<bool> SuggestForTypesInReferenceAssemblies =
new PerLanguageOption<bool>(FeatureName, nameof(SuggestForTypesInReferenceAssemblies), defaultValue: false);
public static PerLanguageOption<bool> SuggestForTypesInNuGetPackages =
new PerLanguageOption<bool>(FeatureName, nameof(SuggestForTypesInNuGetPackages), defaultValue: false);
}
}
// 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 Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Shared.Options
{
[ExportOptionProvider, Shared]
internal class OrganizerOptionsProvider : IOptionProvider
internal class AddImportOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
OrganizerOptions.WarnOnBuildErrors
}.ToImmutableArray();
private readonly IEnumerable<IOption> _options = ImmutableArray.Create<IOption>(
AddImportOptions.SuggestForTypesInReferenceAssemblies,
AddImportOptions.SuggestForTypesInNuGetPackages);
public IEnumerable<IOption> GetOptions()
{
return _options;
}
public IEnumerable<IOption> GetOptions() => _options;
}
}
......@@ -13,13 +13,5 @@ public static PerLanguageOption<bool> PlaceSystemNamespaceFirst
{
get { return Editing.GenerationOptions.PlaceSystemNamespaceFirst; }
}
/// <summary>
/// This option is currently unused by Roslyn, but we might want to implement it in the
/// future. Keeping the option while it's unimplemented allows all upgrade paths to
/// maintain any customized value for this setting, even through versions that have not
/// implemented this feature yet.
/// </summary>
public static readonly PerLanguageOption<bool> WarnOnBuildErrors = new PerLanguageOption<bool>(FeatureName, "WarnOnBuildErrors", defaultValue: true);
}
}
......@@ -13,6 +13,6 @@ internal static class ServiceComponentOnOffOptions
public static readonly Option<bool> DiagnosticProvider = new Option<bool>(OptionName, "Diagnostic Provider", defaultValue: true);
public static readonly Option<bool> PackageSearch = new Option<bool>(OptionName, nameof(PackageSearch), defaultValue: false);
public static readonly Option<bool> SymbolSearch = new Option<bool>(OptionName, nameof(SymbolSearch), defaultValue: true);
}
}
......@@ -14,7 +14,7 @@ internal class ServiceComponentOnOffOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = ImmutableArray.Create(
ServiceComponentOnOffOptions.DiagnosticProvider,
ServiceComponentOnOffOptions.PackageSearch);
ServiceComponentOnOffOptions.SymbolSearch);
public IEnumerable<IOption> GetOptions() => _options;
}
......
......@@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.Formatting
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.Packaging
Imports Microsoft.CodeAnalysis.Simplification
Imports Microsoft.CodeAnalysis.SymbolSearch
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
......@@ -24,7 +25,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
''' <summary>
''' For testing purposes so that tests can pass in mocks for these values.
''' </summary>
Friend Sub New(installerService As IPackageInstallerService, searchService As IPackageSearchService)
Friend Sub New(installerService As IPackageInstallerService,
searchService As ISymbolSearchService)
MyBase.New(installerService, searchService)
End Sub
......
......@@ -537,15 +537,6 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Organize Usings.
/// </summary>
internal static string Option_OrganizeUsings {
get {
return ResourceManager.GetString("Option_OrganizeUsings", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Outlining.
/// </summary>
......@@ -574,7 +565,7 @@ internal class CSharpVSResources {
}
/// <summary>
/// Looks up a localized string similar to Show preview for _rename tracking.
/// Looks up a localized string similar to Show preview for rename _tracking.
/// </summary>
internal static string Option_RenameTrackingPreview {
get {
......@@ -610,11 +601,29 @@ internal class CSharpVSResources {
}
/// <summary>
/// Looks up a localized string similar to Warn if _build errors exist when organizing usings.
/// Looks up a localized string similar to Suggest usings for types in _NuGet packages.
/// </summary>
internal static string Option_Suggest_usings_for_types_in_NuGet_packages {
get {
return ResourceManager.GetString("Option_Suggest_usings_for_types_in_NuGet_packages", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Suggest usings for types in _reference assemblies.
/// </summary>
internal static string Option_Suggest_usings_for_types_in_reference_assemblies {
get {
return ResourceManager.GetString("Option_Suggest_usings_for_types_in_reference_assemblies", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Using Directives.
/// </summary>
internal static string Option_WarnOnBuildErrors {
internal static string Option_Using_Directives {
get {
return ResourceManager.GetString("Option_WarnOnBuildErrors", resourceCulture);
return ResourceManager.GetString("Option_Using_Directives", resourceCulture);
}
}
......
......@@ -369,8 +369,8 @@
<data name="Option_OptimizeForSolutionSize_Small" xml:space="preserve">
<value>Small</value>
</data>
<data name="Option_OrganizeUsings" xml:space="preserve">
<value>Organize Usings</value>
<data name="Option_Using_Directives" xml:space="preserve">
<value>Using Directives</value>
</data>
<data name="Option_Outlining" xml:space="preserve">
<value>Outlining</value>
......@@ -381,9 +381,6 @@
<data name="Option_PlaceSystemNamespaceFirst" xml:space="preserve">
<value>_Place 'System' directives first when sorting usings</value>
</data>
<data name="Option_WarnOnBuildErrors" xml:space="preserve">
<value>Warn if _build errors exist when organizing usings</value>
</data>
<data name="Option_BringUpOnIdentifier" xml:space="preserve">
<value>_Show completion list after a character is typed</value>
</data>
......@@ -403,7 +400,7 @@
<value>Selection In Completion List</value>
</data>
<data name="Option_RenameTrackingPreview" xml:space="preserve">
<value>Show preview for _rename tracking</value>
<value>Show preview for rename _tracking</value>
</data>
<data name="NewLinesForBracesAccessors" xml:space="preserve">
<value>Place open brace on new line for property, indexer, and event accessors</value>
......@@ -411,4 +408,10 @@
<data name="NewLinesForBracesProperty" xml:space="preserve">
<value>Place open brace on new line for properties, indexers, and events</value>
</data>
<data name="Option_Suggest_usings_for_types_in_reference_assemblies" xml:space="preserve">
<value>Suggest usings for types in _reference assemblies</value>
</data>
<data name="Option_Suggest_usings_for_types_in_NuGet_packages" xml:space="preserve">
<value>Suggest usings for types in _NuGet packages</value>
</data>
</root>
\ No newline at end of file
......@@ -11,6 +11,20 @@
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<GroupBox x:Uid="UsingDirectivesGroupBox"
Header="{x:Static local:AdvancedOptionPageStrings.Option_Using_Directives}">
<StackPanel>
<CheckBox x:Name="PlaceSystemNamespaceFirst"
x:Uid="SortUsings_PlaceSystemFirst"
Content="{x:Static local:AdvancedOptionPageStrings.Option_PlaceSystemNamespaceFirst}" />
<CheckBox x:Name="SuggestForTypesInReferenceAssemblies"
x:Uid="AddImport_SuggestForTypesInReferenceAssemblies"
Content="{x:Static local:AdvancedOptionPageStrings.Option_Suggest_usings_for_types_in_reference_assemblies}" />
<CheckBox x:Name="SuggestForTypesInNuGetPackages"
x:Uid="AddImport_SuggestForTypesInNuGetPackages"
Content="{x:Static local:AdvancedOptionPageStrings.Option_Suggest_usings_for_types_in_NuGet_packages}" />
</StackPanel>
</GroupBox>
<GroupBox x:Uid="HighlightingGroupBox"
Header="{x:Static local:AdvancedOptionPageStrings.Option_Highlighting}">
<StackPanel>
......@@ -42,17 +56,6 @@
Content="{x:Static local:AdvancedOptionPageStrings.Option_RenameTrackingPreview}" />
</StackPanel>
</GroupBox>
<GroupBox x:Uid="OrganizeUsingsGroupBox"
Header="{x:Static local:AdvancedOptionPageStrings.Option_OrganizeUsings}">
<StackPanel>
<CheckBox x:Name="WarnOnBuildErrors"
Visibility="Collapsed"
Content="{x:Static local:AdvancedOptionPageStrings.Option_WarnOnBuildErrors}" />
<CheckBox x:Name="PlaceSystemNamespaceFirst"
x:Uid="SortUsings_PlaceSystemFirst"
Content="{x:Static local:AdvancedOptionPageStrings.Option_PlaceSystemNamespaceFirst}" />
</StackPanel>
</GroupBox>
<GroupBox x:Uid="ExtractMethodGroupBox"
Header="{x:Static local:AdvancedOptionPageStrings.Option_ExtractMethod}">
<StackPanel>
......
......@@ -15,6 +15,10 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
{
InitializeComponent();
BindToOption(PlaceSystemNamespaceFirst, OrganizerOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp);
BindToOption(SuggestForTypesInReferenceAssemblies, AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp);
BindToOption(SuggestForTypesInNuGetPackages, AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp);
BindToOption(EnterOutliningMode, FeatureOnOffOptions.Outlining, LanguageNames.CSharp);
BindToOption(GenerateXmlDocCommentsForTripleSlash, FeatureOnOffOptions.AutoXmlDocCommentGeneration, LanguageNames.CSharp);
BindToOption(InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments, FeatureOnOffOptions.AutoInsertBlockCommentStartString, LanguageNames.CSharp);
......@@ -22,7 +26,6 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.CSharp);
BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.CSharp);
BindToOption(RenameTrackingPreview, FeatureOnOffOptions.RenameTrackingPreview, LanguageNames.CSharp);
BindToOption(PlaceSystemNamespaceFirst, OrganizerOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp);
BindToOption(DontPutOutOrRefOnStruct, ExtractMethodOptions.DontPutOutOrRefOnStruct, LanguageNames.CSharp);
BindToOption(AllowMovingDeclaration, ExtractMethodOptions.AllowMovingDeclaration, LanguageNames.CSharp);
BindToFullSolutionAnalysisOption(ClosedFileDiagnostics, LanguageNames.CSharp);
......
......@@ -89,11 +89,6 @@ public static string Option_OptimizeForSolutionSize_Small
get { return CSharpVSResources.Option_OptimizeForSolutionSize_Small; }
}
public static string Option_OrganizeUsings
{
get { return CSharpVSResources.Option_OrganizeUsings; }
}
public static string Option_Outlining
{
get { return CSharpVSResources.Option_Outlining; }
......@@ -109,9 +104,13 @@ public static string Option_PlaceSystemNamespaceFirst
get { return CSharpVSResources.Option_PlaceSystemNamespaceFirst; }
}
public static string Option_WarnOnBuildErrors
{
get { return CSharpVSResources.Option_WarnOnBuildErrors; }
}
public static string Option_Using_Directives =>
CSharpVSResources.Option_Using_Directives;
public static string Option_Suggest_usings_for_types_in_reference_assemblies =>
CSharpVSResources.Option_Suggest_usings_for_types_in_reference_assemblies;
public static string Option_Suggest_usings_for_types_in_NuGet_packages =>
CSharpVSResources.Option_Suggest_usings_for_types_in_NuGet_packages;
}
}
......@@ -300,6 +300,18 @@ public int SortUsings_PlaceSystemFirst
set { SetBooleanOption(OrganizerOptions.PlaceSystemNamespaceFirst, value); }
}
public int AddImport_SuggestForTypesInReferenceAssemblies
{
get { return GetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies); }
set { SetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, value); }
}
public int AddImport_SuggestForTypesInNuGetPackages
{
get { return GetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages); }
set { SetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages, value); }
}
public int Space_AfterBasesColon
{
get { return GetBooleanOption(CSharpFormattingOptions.SpaceAfterColonInBaseTypeDeclaration); }
......@@ -473,12 +485,6 @@ public int Style_UseVarWhenDeclaringLocals
set { SetBooleanOption(CSharpCodeStyleOptions.UseVarWhenDeclaringLocals, value); }
}
public int WarnOnBuildErrors
{
get { return GetBooleanOption(OrganizerOptions.WarnOnBuildErrors); }
set { SetBooleanOption(OrganizerOptions.WarnOnBuildErrors, value); }
}
public int Wrapping_IgnoreSpacesAroundBinaryOperators
{
get
......
......@@ -33,6 +33,7 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options
[ExportLanguageSpecificOptionSerializer(
LanguageNames.CSharp,
OrganizerOptions.FeatureName,
AddImportOptions.FeatureName,
CompletionOptions.FeatureName,
CSharpCompletionOptions.FeatureName,
CSharpCodeStyleOptions.FeatureName,
......@@ -82,6 +83,7 @@ private bool ShouldIncludeOnOffOption(FieldInfo fieldInfo)
Type[] types = new[]
{
typeof(OrganizerOptions),
typeof(AddImportOptions),
typeof(CSharpCompletionOptions),
typeof(SimplificationOptions),
typeof(CSharpCodeStyleOptions),
......@@ -120,7 +122,8 @@ protected override string GetStorageKeyForOption(IOption option)
protected override bool SupportsOption(IOption option, string languageName)
{
if (option == OrganizerOptions.PlaceSystemNamespaceFirst ||
option == OrganizerOptions.WarnOnBuildErrors ||
option == AddImportOptions.SuggestForTypesInReferenceAssemblies ||
option == AddImportOptions.SuggestForTypesInNuGetPackages ||
option == CSharpCompletionOptions.AddNewLineOnEnterAfterFullyTypedWord ||
option == CSharpCompletionOptions.IncludeSnippets ||
option.Feature == CSharpCodeStyleOptions.FeatureName ||
......
......@@ -16,11 +16,13 @@
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Feedback.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Extensions;
using Microsoft.VisualStudio.LanguageServices.Packaging;
using Microsoft.VisualStudio.LanguageServices.SymbolSearch;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
......@@ -55,7 +57,7 @@ internal abstract class VisualStudioWorkspaceImpl : VisualStudioWorkspace
private readonly ForegroundThreadAffinitizedObject _foregroundObject = new ForegroundThreadAffinitizedObject();
private PackageInstallerService _packageInstallerService;
private PackageSearchService _packageSearchService;
private SymbolSearchService _symbolSearchService;
public VisualStudioWorkspaceImpl(
SVsServiceProvider serviceProvider,
......@@ -111,7 +113,7 @@ protected void InitializeStandardVisualStudioWorkspace(SVsServiceProvider servic
this.Services.GetService<IOptionService>();
// Ensure the nuget package services are initialized on the UI thread.
_packageSearchService = this.Services.GetService<IPackageSearchService>() as PackageSearchService;
_symbolSearchService = this.Services.GetService<ISymbolSearchService>() as SymbolSearchService;
_packageInstallerService = (PackageInstallerService)this.Services.GetService<IPackageInstallerService>();
_packageInstallerService.Connect(this);
}
......@@ -1010,7 +1012,7 @@ internal void StopSolutionCrawler()
protected override void Dispose(bool finalize)
{
_packageInstallerService?.Disconnect(this);
_packageSearchService?.Dispose();
_symbolSearchService?.Dispose();
// workspace is going away. unregister this workspace from work coordinator
StopSolutionCrawler();
......
......@@ -80,7 +80,7 @@ internal void Connect(VisualStudioWorkspaceImpl workspace)
this.AssertIsForeground();
var options = workspace.Options;
if (!options.GetOption(ServiceComponentOnOffOptions.PackageSearch))
if (!options.GetOption(ServiceComponentOnOffOptions.SymbolSearch))
{
return;
}
......
......@@ -156,23 +156,23 @@
<Compile Include="Implementation\Workspace\VisualStudioProjectCacheHostServiceFactory.cs" />
<Compile Include="IRoslynTelemetrySetup.cs" />
<Compile Include="Packaging\Interop\SVsRemoteControlService.cs" />
<Compile Include="Packaging\IPackageSearchDatabaseFactoryService.cs" />
<Compile Include="Packaging\IPackageSearchDelayService.cs" />
<Compile Include="Packaging\IPackageSearchIOService.cs" />
<Compile Include="Packaging\IPackageSearchLogService.cs" />
<Compile Include="Packaging\IPackageSearchPatchService.cs" />
<Compile Include="Packaging\IPackageSearchRemoteControlService.cs" />
<Compile Include="SymbolSearch\IDatabaseFactoryService.cs" />
<Compile Include="SymbolSearch\IDelayService.cs" />
<Compile Include="SymbolSearch\IIOService.cs" />
<Compile Include="SymbolSearch\ILogService.cs" />
<Compile Include="SymbolSearch\IPatchService.cs" />
<Compile Include="SymbolSearch\IRemoteControlService.cs" />
<Compile Include="Packaging\PackageInstallerServiceFactory.cs" />
<Compile Include="Packaging\PackageInstallerServiceFactory_UndoRedo.cs" />
<Compile Include="Packaging\PackageSearchService.Update.cs" />
<Compile Include="Packaging\PackageSearchService.cs" />
<Compile Include="Packaging\PackageSearchService.DatabaseFactoryService.cs" />
<Compile Include="Packaging\PackageSearchService.DelayService.cs" />
<Compile Include="Packaging\PackageSearchService.IOService.cs" />
<Compile Include="Packaging\PackageSearchService.LogService.cs" />
<Compile Include="Packaging\PackageSearchService.RemoteControlService.cs" />
<Compile Include="Packaging\PackageSearchServiceFactory.cs" />
<Compile Include="Packaging\Patching\Delta.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.Update.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.DatabaseFactoryService.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.DelayService.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.IOService.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.LogService.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.RemoteControlService.cs" />
<Compile Include="SymbolSearch\SymbolSearchServiceFactory.cs" />
<Compile Include="SymbolSearch\Patching\Delta.cs" />
<Compile Include="RoslynPackage.cs" />
<Compile Include="ServicesVSResources.Designer.cs">
<AutoGen>True</AutoGen>
......@@ -743,7 +743,7 @@
<Compile Include="Implementation\ProjectSystem\MetadataReferences\VisualStudioMetadataReferenceManager.Factory.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Packaging\PackageSearchService.PatchService.cs" />
<Compile Include="SymbolSearch\SymbolSearchService.PatchService.cs" />
<None Include="project.json" />
<PublicAPI Include="PublicAPI.Shipped.txt" />
<PublicAPI Include="PublicAPI.Unshipped.txt" />
......
......@@ -2,9 +2,9 @@
using Microsoft.CodeAnalysis.Elfie.Model;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal interface IPackageSearchDatabaseFactoryService
internal interface IDatabaseFactoryService
{
AddReferenceDatabase CreateDatabaseFromBytes(byte[] bytes);
}
......
// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
/// <summary>
/// Used so we can mock out how the search service delays work for testing purposes.
/// </summary>
internal interface IPackageSearchDelayService
internal interface IDelayService
{
/// <summary>
/// The time to wait after a successful update (default = 1 day).
......
// 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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
/// <summary>
/// Used so we can mock out how the search service does IO for testing purposes.
/// </summary>
internal interface IPackageSearchIOService
internal interface IIOService
{
void Create(DirectoryInfo directory);
void Delete(FileInfo file);
......
// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
/// <summary>
/// Used so we can mock out logging in unit tests.
/// </summary>
internal interface IPackageSearchLogService
internal interface ILogService
{
void LogException(Exception e, string text);
void LogInfo(string text);
......
// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
/// <summary>
/// Used so we can mock out patching in unit tests.
/// </summary>
internal interface IPackageSearchPatchService
internal interface IPatchService
{
byte[] ApplyPatch(byte[] databaseBytes, byte[] patchBytes);
}
......
......@@ -5,20 +5,20 @@
using System.Threading.Tasks;
using Microsoft.Internal.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
/// <summary>
/// Used so we can mock out the remote control service in unit tests.
/// </summary>
internal interface IPackageSearchRemoteControlService
internal interface IRemoteControlService
{
IPackageSearchRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes);
IRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes);
}
/// <summary>
/// Used so we can mock out the client in unit tests.
/// </summary>
internal interface IPackageSearchRemoteControlClient : IDisposable
internal interface IRemoteControlClient : IDisposable
{
Task<Stream> ReadFileAsync(__VsRemoteControlBehaviorOnStale behavior);
}
......
......@@ -8,7 +8,7 @@
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.VisualStudio.LanguageServices.Packaging.Patching
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch.Patching
{
/// <summary>
/// Wrapper around the msdelta api so we can consume patches produced by the Elfie service.
......
......@@ -3,11 +3,11 @@
using System.IO;
using Microsoft.CodeAnalysis.Elfie.Model;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal partial class PackageSearchService
internal partial class SymbolSearchService
{
private class DatabaseFactoryService : IPackageSearchDatabaseFactoryService
private class DatabaseFactoryService : IDatabaseFactoryService
{
public AddReferenceDatabase CreateDatabaseFromBytes(byte[] bytes)
{
......
......@@ -2,11 +2,11 @@
using System;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal partial class PackageSearchService
internal partial class SymbolSearchService
{
private class DelayService : IPackageSearchDelayService
private class DelayService : IDelayService
{
public TimeSpan CachePollDelay { get; } = TimeSpan.FromMinutes(1);
public TimeSpan FileWriteDelay { get; } = TimeSpan.FromSeconds(10);
......
......@@ -3,11 +3,11 @@
using System.Collections.Generic;
using System.IO;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal partial class PackageSearchService
internal partial class SymbolSearchService
{
private class IOService : IPackageSearchIOService
private class IOService : IIOService
{
public void Create(DirectoryInfo directory) => directory.Create();
......
......@@ -4,11 +4,11 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal partial class PackageSearchService
internal partial class SymbolSearchService
{
private class LogService : ForegroundThreadAffinitizedObject, IPackageSearchLogService
private class LogService : ForegroundThreadAffinitizedObject, ILogService
{
private readonly IVsActivityLog _activityLog;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal partial class PackageSearchService
internal partial class SymbolSearchService
{
private class PatchService : IPackageSearchPatchService
private class PatchService : IPatchService
{
public byte[] ApplyPatch(byte[] databaseBytes, byte[] patchBytes)
{
......
......@@ -6,11 +6,11 @@
using System.Threading.Tasks;
using Microsoft.Internal.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
internal partial class PackageSearchService
internal partial class SymbolSearchService
{
private class RemoteControlService : IPackageSearchRemoteControlService
private class RemoteControlService : IRemoteControlService
{
private readonly object _remoteControlService;
......@@ -19,7 +19,7 @@ public RemoteControlService(object remoteControlService)
_remoteControlService = remoteControlService;
}
public IPackageSearchRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes)
public IRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes)
{
var serviceType = _remoteControlService.GetType();
var serviceAssembly = serviceType.Assembly;
......@@ -39,7 +39,7 @@ public IPackageSearchRemoteControlClient CreateClient(string hostId, string serv
}
}
private class RemoteControlClient : IPackageSearchRemoteControlClient
private class RemoteControlClient : IRemoteControlClient
{
// Have to keep the vsClient around as it will try to dispose the underlying
// client when it gets GC'ed
......
......@@ -17,8 +17,12 @@
using Microsoft.Internal.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
using static System.FormattableString;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Shared.Options;
using System.Linq;
using System.Collections.Immutable;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
/// <summary>
/// A service which enables searching for packages matching certain criteria.
......@@ -27,7 +31,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Packaging
/// This implementation also spawns a task which will attempt to keep that database up to
/// date by downloading patches on a daily basis.
/// </summary>
internal partial class PackageSearchService
internal partial class SymbolSearchService
{
// Internal for testing purposes.
internal const string ContentAttributeName = "content";
......@@ -49,6 +53,8 @@ internal partial class PackageSearchService
private readonly CancellationTokenSource _cancellationTokenSource;
private readonly CancellationToken _cancellationToken;
private readonly Workspace _workspace;
private readonly ConcurrentDictionary<string, object> _sourceToUpdateSentinel =
new ConcurrentDictionary<string, object>();
......@@ -58,12 +64,12 @@ internal partial class PackageSearchService
// Interfaces that abstract out the external functionality we need. Used so we can easily
// mock behavior during tests.
private readonly IPackageInstallerService _installerService;
private readonly IPackageSearchDelayService _delayService;
private readonly IPackageSearchIOService _ioService;
private readonly IPackageSearchLogService _logService;
private readonly IPackageSearchRemoteControlService _remoteControlService;
private readonly IPackageSearchPatchService _patchService;
private readonly IPackageSearchDatabaseFactoryService _databaseFactoryService;
private readonly IDelayService _delayService;
private readonly IIOService _ioService;
private readonly ILogService _logService;
private readonly IRemoteControlService _remoteControlService;
private readonly IPatchService _patchService;
private readonly IDatabaseFactoryService _databaseFactoryService;
private readonly Func<Exception, bool> _reportAndSwallowException;
public void Dispose()
......@@ -76,12 +82,27 @@ public void Dispose()
private void LogException(Exception e, string text) => _logService.LogException(e, text);
private void OnPackageSourcesChanged(object sender, EventArgs e)
private void OnOptionChanged(object sender, EventArgs e)
{
var options = _workspace.Options;
if (!options.GetOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp) &&
!options.GetOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic) &&
!options.GetOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp) &&
!options.GetOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic))
{
// If we don't have any add-import features that would use these indices, then
// don't bother creating them.
return;
}
// Kick off a database update. Wait a few seconds before starting so we don't
// interfere too much with solution loading.
var sources = _installerService.PackageSources;
foreach (var source in sources)
// Always pull down the nuget.org index. It contains the MS reference assembly index
// inside of it.
var allSources = sources.Concat(new PackageSource(NugetOrgSource, source: null));
foreach (var source in allSources)
{
Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(_ =>
UpdateSourceInBackgroundAsync(source.Name), TaskScheduler.Default);
......@@ -109,11 +130,11 @@ internal Task UpdateSourceInBackgroundAsync(string source)
private class Updater
{
private readonly PackageSearchService _service;
private readonly SymbolSearchService _service;
private readonly string _source;
private readonly FileInfo _databaseFileInfo;
public Updater(PackageSearchService service, string source)
public Updater(SymbolSearchService service, string source)
{
_service = service;
_source = source;
......@@ -541,7 +562,7 @@ private async Task<XElement> DownloadFileAsync(string serverPath)
}
/// <summary>Returns 'null' if download is not available and caller should keep polling.</summary>
private async Task<XElement> TryDownloadFileAsync(IPackageSearchRemoteControlClient client)
private async Task<XElement> TryDownloadFileAsync(IRemoteControlClient client)
{
_service.LogInfo("Read file from client");
......
......@@ -6,13 +6,15 @@
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Elfie.Model;
using Microsoft.CodeAnalysis.Elfie.Model.Structures;
using Microsoft.CodeAnalysis.Elfie.Model.Tree;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.Internal.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell.Interop;
......@@ -20,7 +22,7 @@
using static System.FormattableString;
using VSShell = Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
/// <summary>
/// A service which enables searching for packages matching certain criteria.
......@@ -29,16 +31,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Packaging
/// This implementation also spawns a task which will attempt to keep that database up to
/// date by downloading patches on a daily basis.
/// </summary>
internal partial class PackageSearchService :
internal partial class SymbolSearchService :
ForegroundThreadAffinitizedObject,
IPackageSearchService,
IReferenceAssemblySearchService,
ISymbolSearchService,
IDisposable
{
private ConcurrentDictionary<string, AddReferenceDatabase> _sourceToDatabase = new ConcurrentDictionary<string, AddReferenceDatabase>();
public PackageSearchService(VSShell.SVsServiceProvider serviceProvider, IPackageInstallerService installerService)
: this(installerService,
public SymbolSearchService(
VSShell.SVsServiceProvider serviceProvider,
Workspace workspace,
IPackageInstallerService installerService)
: this(workspace,
installerService,
CreateRemoteControlService(serviceProvider),
new LogService((IVsActivityLog)serviceProvider.GetService(typeof(SVsActivityLog))),
new DelayService(),
......@@ -50,11 +55,14 @@ public PackageSearchService(VSShell.SVsServiceProvider serviceProvider, IPackage
FatalError.ReportWithoutCrash,
new CancellationTokenSource())
{
installerService.PackageSourcesChanged += OnPackageSourcesChanged;
OnPackageSourcesChanged(this, EventArgs.Empty);
installerService.PackageSourcesChanged += OnOptionChanged;
var optionsService = workspace.Services.GetService<IOptionService>();
optionsService.OptionChanged += OnOptionChanged;
OnOptionChanged(this, EventArgs.Empty);
}
private static IPackageSearchRemoteControlService CreateRemoteControlService(VSShell.SVsServiceProvider serviceProvider)
private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServiceProvider serviceProvider)
{
var vsService = serviceProvider.GetService(typeof(SVsRemoteControlService));
if (vsService == null)
......@@ -69,14 +77,15 @@ private static IPackageSearchRemoteControlService CreateRemoteControlService(VSS
/// <summary>
/// For testing purposes only.
/// </summary>
internal PackageSearchService(
internal SymbolSearchService(
Workspace workspace,
IPackageInstallerService installerService,
IPackageSearchRemoteControlService remoteControlService,
IPackageSearchLogService logService,
IPackageSearchDelayService delayService,
IPackageSearchIOService ioService,
IPackageSearchPatchService patchService,
IPackageSearchDatabaseFactoryService databaseFactoryService,
IRemoteControlService remoteControlService,
ILogService logService,
IDelayService delayService,
IIOService ioService,
IPatchService patchService,
IDatabaseFactoryService databaseFactoryService,
string localSettingsDirectory,
Func<Exception, bool> reportAndSwallowException,
CancellationTokenSource cancellationTokenSource)
......@@ -87,6 +96,7 @@ private static IPackageSearchRemoteControlService CreateRemoteControlService(VSS
return;
}
_workspace = workspace;
_installerService = installerService;
_delayService = delayService;
_ioService = ioService;
......
......@@ -8,18 +8,19 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.SymbolSearch;
using Roslyn.Utilities;
using VSShell = Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
[ExportWorkspaceServiceFactory(typeof(IPackageSearchService), WorkspaceKind.Host), Shared]
internal class PackageSearchServiceFactory : IWorkspaceServiceFactory
[ExportWorkspaceServiceFactory(typeof(ISymbolSearchService), WorkspaceKind.Host), Shared]
internal class SymbolSearchServiceFactory : IWorkspaceServiceFactory
{
private readonly VSShell.SVsServiceProvider _serviceProvider;
[ImportingConstructor]
public PackageSearchServiceFactory(
public SymbolSearchServiceFactory(
VSShell.SVsServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
......@@ -28,25 +29,33 @@ internal class PackageSearchServiceFactory : IWorkspaceServiceFactory
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
var options = workspaceServices.Workspace.Options;
if (options.GetOption(ServiceComponentOnOffOptions.PackageSearch))
if (options.GetOption(ServiceComponentOnOffOptions.SymbolSearch))
{
// Only support package search in vs workspace.
if (workspaceServices.Workspace is VisualStudioWorkspace)
{
return new PackageSearchService(_serviceProvider, workspaceServices.GetService<IPackageInstallerService>());
return new SymbolSearchService(
_serviceProvider, workspaceServices.Workspace,
workspaceServices.GetService<IPackageInstallerService>());
}
}
return new NullPackageSearchService();
return new NullSymbolSearchService();
}
private class NullPackageSearchService : IPackageSearchService
private class NullSymbolSearchService : ISymbolSearchService
{
public IEnumerable<PackageWithTypeResult> FindPackagesWithType(
string source, string name, int arity, CancellationToken cancellationToken)
{
return SpecializedCollections.EmptyEnumerable<PackageWithTypeResult>();
}
public IEnumerable<ReferenceAssemblyWithTypeResult> FindReferenceAssembliesWithType(
string name, int arity, CancellationToken cancellationToken)
{
return SpecializedCollections.EmptyEnumerable<ReferenceAssemblyWithTypeResult>();
}
}
}
}
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.IO
Imports System.IO.Compression
Imports System.Threading
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Elfie.Model
Imports Microsoft.CodeAnalysis.Packaging
Imports Microsoft.Internal.VisualStudio.Shell.Interop
Imports Microsoft.VisualStudio.LanguageServices.Packaging
Imports Moq
Imports Roslyn.Test.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Packaging
Public Class PackageSearchServiceTests
Private Shared ReadOnly s_allButMoqExceptions As Func(Of Exception, Boolean) =
Function(e) TypeOf e IsNot MockException
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function CreateCacheFolderIfMissing() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)(MockBehavior.Strict)
' Simulate the cache folder being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Expect that the cache directory is created. Cancel processing at that point so
' the test can complete.
ioMock.Setup(Sub(s) s.Create(It.IsAny(Of DirectoryInfo))).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim remoteControlService = New Mock(Of IPackageSearchRemoteControlService)
Dim service = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlService.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await service.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlService.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function DoNotCreateCacheFolderIfItIsThere() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)(MockBehavior.Strict)
' Simulate the cache folder being there. We use a 'strict' mock so that
' we'll throw if we get the call to create the directory.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of DirectoryInfo))).Returns(True).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim remoteControlService = New Mock(Of IPackageSearchRemoteControlService)
Dim service = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlService.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await service.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlService.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function DownloadFullDatabaseWhenLocalDatabaseIsMissing() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simlute the local database being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient)
Dim serviceMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict)
' The client should request the 'Latest' database from the server.
' Cancel processing at that point so the test can complete.
serviceMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=serviceMock.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
serviceMock.Verify()
clientMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function FailureToParseFullDBAtXmlLevelTakesCatastrophicPath() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simlute the local database being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = CreateClientMock(CreateStream(New XElement("Database",
New XAttribute(PackageSearchService.ContentAttributeName, ""),
New XAttribute(PackageSearchService.ChecksumAttributeName, Convert.ToBase64String(New Byte() {0, 1, 2})))))
Dim serviceMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict)
' The client should request the 'Latest' database from the server.
' Cancel processing at that point so the test can complete.
serviceMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object)
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=serviceMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
serviceMock.Verify()
clientMock.Verify()
delayMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function TestClientDisposedAfterUse() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient)(MockBehavior.Strict)
clientMock.Setup(Sub(c) c.Dispose())
Dim serviceMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict)
serviceMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))).
Returns(clientMock.Object).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=serviceMock.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
serviceMock.Verify()
clientMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function CrashInClientRunsFailureLoopPath() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simulate the database not being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient)(MockBehavior.Strict)
' We should get a call to try to read the file. Simulate a crash in the client.
clientMock.Setup(Sub(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))).
Throws(New NotImplementedException())
' Client should be disposed.
clientMock.Setup(Sub(c) c.Dispose())
Dim remoteControlMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict)
remoteControlMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))).
Returns(clientMock.Object)
' Because the client failed we will expect to call into the 'UpdateFailedDelay' to
' control when we do our next loop.
' Cancel processing at that point so the test can complete.
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
delayMock.SetupGet(Function(s) s.ExpectedFailureDelay).Returns(TimeSpan.Zero).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function FailureToParseFullDBAtElfieLevelTakesCatastrophicPath() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
'Simulate the database file not existing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Get a client that will download the latest database.
Dim clientMock = CreateFullDatabaseClientMock()
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True)
Dim factoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict)
' Simulate Elfie throwing when trying to make a database from the contents of that response
factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Throws(New NotImplementedException())
' Because the parsing failed we will expect to call into the 'UpdateFailedDelay' to
' control when we do our next loop.
' Cancel processing at that point so the test can complete.
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=factoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
factoryMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function SuccessParsingDBWritesToDisk() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simulate the local database not being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Create a client that will download the latest database.
Dim clientMock = CreateFullDatabaseClientMock()
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True)
' Successfully create a database from that response.
Dim factoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict)
factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=factoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
factoryMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function WriteAgainOnIOFailure() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simulate the database being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Create a client that will download the latest databsae
Dim clientMock = CreateFullDatabaseClientMock()
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True)
' Create a database from the client response.
Dim factoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict)
factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
' Write the temp file out to disk.
ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsAny(Of String), It.IsAny(Of Byte())))
' Simulate a failure doing the first 'replace' of the database file.
ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean))).
Throws(New IOException())
' We'll expect to have to replay the write. So we should get a call to 'FileWriteDelay'
delayMock.SetupGet(Function(s) s.FileWriteDelay).Returns(TimeSpan.Zero)
' Succeed on the second write attempt.
ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean)))
' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=factoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
factoryMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_UpToDate_DoesNothing() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch that says things are up to date.
Dim clientMock = CreatePatchClientMock(isUpToDate:=True)
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
' Because everything is up to date, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_IsTooOldCausesFullDownload() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch that says things are too old.
Dim clientMock = CreatePatchClientMock(isTooOld:=True)
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
' This should cause us to want to then download the full db. So now
' setup an expectation that we'll download the latest.
Dim clientMock2 = CreateFullDatabaseClientMock()
SetupDownloadLatest(remoteControlMock, clientMock2)
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
' Because we got the full database, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
clientMock2.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_FailureToPatchCausesFullDownload() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch with contents.
Dim clientMock = CreatePatchClientMock(contents:="")
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
' Simulate a crash in the patching process.
Dim patchService = New Mock(Of IPackageSearchPatchService)(MockBehavior.Strict)
patchService.Setup(Sub(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))).
Throws(New NotImplementedException())
' This should cause us to want to then download the full db. So now
' setup an expectation that we'll download the latest.
Dim clientMock2 = CreateFullDatabaseClientMock()
SetupDownloadLatest(remoteControlMock, clientMock2)
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
clientMock2.Verify()
patchService.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_SuccessfulPatchWritesToDisk() As Task
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IPackageSearchIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch with contents.
Dim clientMock = CreatePatchClientMock(contents:="")
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
' Simulate a crash in the patching process.
Dim patchMock = New Mock(Of IPackageSearchPatchService)(MockBehavior.Strict)
patchMock.Setup(Function(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))).
Returns(New Byte() {0})
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict)
' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New PackageSearchService(
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=patchMock.Object,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
patchMock.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Function
Private Shared Sub SetupWritesDatabaseSuccessfullyToDisk(ioMock As Mock(Of IPackageSearchIOService))
' Expect that we'll write out the temp file.
ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsRegex(".*tmp"), It.IsAny(Of Byte())))
' Expect that we'll replace the existing file with the temp file.
ioMock.Setup(Sub(s) s.Replace(It.IsRegex(".*tmp"), It.IsRegex(".*txt"), Nothing, It.IsAny(Of Boolean)))
End Sub
Private Shared Function CreateRemoteControlServiceMock(
clientMock As Mock(Of IPackageSearchRemoteControlClient),
latest As Boolean) As Mock(Of IPackageSearchRemoteControlService)
Dim remoteControlMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict)
If latest Then
SetupDownloadLatest(remoteControlMock, clientMock)
Else
SetupDownloadPatch(clientMock, remoteControlMock)
End If
Return remoteControlMock
End Function
Private Shared Sub SetupDownloadPatch(clientMock As Mock(Of IPackageSearchRemoteControlClient), remoteControlMock As Mock(Of IPackageSearchRemoteControlService))
remoteControlMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Patch.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object)
End Sub
Private Shared Sub SetupDownloadLatest(remoteControlMock As Mock(Of IPackageSearchRemoteControlService), clientMock As Mock(Of IPackageSearchRemoteControlClient))
remoteControlMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object)
End Sub
Private Function CreateFullDatabaseClientMock() As Mock(Of IPackageSearchRemoteControlClient)
Return CreateClientMock(CreateFullDownloadElementStream())
End Function
Private Function CreateClientMock(stream As Stream) As Mock(Of IPackageSearchRemoteControlClient)
Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient)(MockBehavior.Strict)
' Return a full database element when the service asks for it.
clientMock.Setup(Function(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))).
Returns(Task.FromResult(stream))
' Always dispose the client when we get a response.
clientMock.Setup(Sub(c) c.Dispose())
Return clientMock
End Function
Private Function CreatePatchClientMock(Optional isUpToDate As Boolean = False,
Optional isTooOld As Boolean = False,
Optional contents As String = Nothing) As Mock(Of IPackageSearchRemoteControlClient)
Return CreateClientMock(CreatePatchElementStream(isUpToDate, isTooOld, contents))
End Function
Private Function CreatePatchElementStream(Optional isUpToDate As Boolean = False,
Optional isTooOld As Boolean = False,
Optional contents As String = Nothing) As Stream
Dim element = New XElement("Patch",
If(isUpToDate, New XAttribute(PackageSearchService.UpToDateAttributeName, True), Nothing),
If(isTooOld, New XAttribute(PackageSearchService.TooOldAttributeName, True), Nothing),
If(contents IsNot Nothing, New XAttribute(PackageSearchService.ContentAttributeName, contents), Nothing))
Return CreateStream(element)
End Function
Private Function CreateFullDownloadElementStream() As Stream
Dim saveStream = New MemoryStream()
Dim zipStream = New DeflateStream(saveStream, CompressionMode.Compress)
zipStream.Write(New Byte() {0}, 0, 1)
zipStream.Flush()
Dim contents = Convert.ToBase64String(saveStream.ToArray())
Return CreateStream(New XElement("Database",
New XAttribute(PackageSearchService.ContentAttributeName, contents)))
End Function
Private Function CreateStream(element As XElement) As Stream
Dim stream = New MemoryStream()
element.Save(stream)
stream.Position = 0
Return stream
End Function
Private Class TestDelayService
Implements IPackageSearchDelayService
Public Shared ReadOnly Instance As TestDelayService = New TestDelayService()
Private Sub New()
End Sub
Public ReadOnly Property CachePollDelay As TimeSpan Implements IPackageSearchDelayService.CachePollDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property FileWriteDelay As TimeSpan Implements IPackageSearchDelayService.FileWriteDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property ExpectedFailureDelay As TimeSpan Implements IPackageSearchDelayService.ExpectedFailureDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property UpdateSucceededDelay As TimeSpan Implements IPackageSearchDelayService.UpdateSucceededDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property CatastrophicFailureDelay As TimeSpan Implements IPackageSearchDelayService.CatastrophicFailureDelay
Get
Return TimeSpan.Zero
End Get
End Property
End Class
Private Class TestInstallerService
Implements IPackageInstallerService
Public Shared ReadOnly Instance As IPackageInstallerService = New TestInstallerService()
Public ReadOnly Property IsEnabled As Boolean Implements IPackageInstallerService.IsEnabled
Get
Return True
End Get
End Property
Public ReadOnly Property PackageSources As ImmutableArray(Of PackageSource) Implements IPackageInstallerService.PackageSources
Get
Throw New NotImplementedException()
End Get
End Property
Public Event PackageSourcesChanged As EventHandler Implements IPackageInstallerService.PackageSourcesChanged
Public Sub ShowManagePackagesDialog(packageName As String) Implements IPackageInstallerService.ShowManagePackagesDialog
Throw New NotImplementedException()
End Sub
Public Iterator Function GetInstalledVersions(packageName As String) As IEnumerable(Of String) Implements IPackageInstallerService.GetInstalledVersions
End Function
Public Function GetProjectsWithInstalledPackage(solution As Solution, packageName As String, version As String) As IEnumerable(Of Project) Implements IPackageInstallerService.GetProjectsWithInstalledPackage
Throw New NotImplementedException()
End Function
Public Function IsInstalled(workspace As Workspace, projectId As ProjectId, packageName As String) As Boolean Implements IPackageInstallerService.IsInstalled
Throw New NotImplementedException()
End Function
Public Function TryInstallPackage(workspace As Workspace, documentId As DocumentId, source As String, packageName As String, versionOpt As String, cancellationToken As CancellationToken) As Boolean Implements IPackageInstallerService.TryInstallPackage
Throw New NotImplementedException()
End Function
End Class
Private Class TestLogService
Implements IPackageSearchLogService
Public Shared ReadOnly Instance As TestLogService = New TestLogService()
Private Sub New()
End Sub
Public Sub LogException(e As Exception, text As String) Implements IPackageSearchLogService.LogException
End Sub
Public Sub LogInfo(text As String) Implements IPackageSearchLogService.LogInfo
End Sub
End Class
End Class
End Namespace
\ No newline at end of file
......@@ -310,7 +310,7 @@
<Compile Include="Help\HelpTests.vb" />
<Compile Include="LanguageBlockTests.vb" />
<Compile Include="MockComponentModel.vb" />
<Compile Include="Packaging\PackageSearchServiceTests.vb" />
<Compile Include="SymbolSearch\SymbolSearchServiceTests.vb" />
<Compile Include="Utilities\VsNavInfoHelpers.vb" />
<Compile Include="VsNavInfo\VsNavInfoTests.vb" />
<Compile Include="ObjectBrowser\AbstractObjectBrowserTests.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.IO
Imports System.IO.Compression
Imports System.Threading
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Elfie.Model
Imports Microsoft.CodeAnalysis.Packaging
Imports Microsoft.Internal.VisualStudio.Shell.Interop
Imports Microsoft.VisualStudio.LanguageServices.SymbolSearch
Imports Moq
Imports Roslyn.Test.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch
Public Class SymbolSearchServiceTests
Private Shared ReadOnly s_allButMoqExceptions As Func(Of Exception, Boolean) =
Function(e) TypeOf e IsNot MockException
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function CreateCacheFolderIfMissing() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)(MockBehavior.Strict)
' Simulate the cache folder being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Expect that the cache directory is created. Cancel processing at that point so
' the test can complete.
ioMock.Setup(Sub(s) s.Create(It.IsAny(Of DirectoryInfo))).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim remoteControlService = New Mock(Of IRemoteControlService)
Dim service = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlService.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await service.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlService.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function DoNotCreateCacheFolderIfItIsThere() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)(MockBehavior.Strict)
' Simulate the cache folder being there. We use a 'strict' mock so that
' we'll throw if we get the call to create the directory.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of DirectoryInfo))).Returns(True).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim remoteControlService = New Mock(Of IRemoteControlService)
Dim service = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlService.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await service.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlService.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function DownloadFullDatabaseWhenLocalDatabaseIsMissing() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simlute the local database being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = New Mock(Of IRemoteControlClient)
Dim serviceMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict)
' The client should request the 'Latest' database from the server.
' Cancel processing at that point so the test can complete.
serviceMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=serviceMock.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
serviceMock.Verify()
clientMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function FailureToParseFullDBAtXmlLevelTakesCatastrophicPath() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simlute the local database being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = CreateClientMock(CreateStream(New XElement("Database",
New XAttribute(SymbolSearchService.ContentAttributeName, ""),
New XAttribute(SymbolSearchService.ChecksumAttributeName, Convert.ToBase64String(New Byte() {0, 1, 2})))))
Dim serviceMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict)
' The client should request the 'Latest' database from the server.
' Cancel processing at that point so the test can complete.
serviceMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object)
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=serviceMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
serviceMock.Verify()
clientMock.Verify()
delayMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function TestClientDisposedAfterUse() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = New Mock(Of IRemoteControlClient)(MockBehavior.Strict)
clientMock.Setup(Sub(c) c.Dispose())
Dim serviceMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict)
serviceMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))).
Returns(clientMock.Object).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=serviceMock.Object,
logService:=TestLogService.Instance,
delayService:=TestDelayService.Instance,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
serviceMock.Verify()
clientMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function CrashInClientRunsFailureLoopPath() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simulate the database not being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
Dim clientMock = New Mock(Of IRemoteControlClient)(MockBehavior.Strict)
' We should get a call to try to read the file. Simulate a crash in the client.
clientMock.Setup(Sub(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))).
Throws(New NotImplementedException())
' Client should be disposed.
clientMock.Setup(Sub(c) c.Dispose())
Dim remoteControlMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict)
remoteControlMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))).
Returns(clientMock.Object)
' Because the client failed we will expect to call into the 'UpdateFailedDelay' to
' control when we do our next loop.
' Cancel processing at that point so the test can complete.
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
delayMock.SetupGet(Function(s) s.ExpectedFailureDelay).Returns(TimeSpan.Zero).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=Nothing,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function FailureToParseFullDBAtElfieLevelTakesCatastrophicPath() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
'Simulate the database file not existing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Get a client that will download the latest database.
Dim clientMock = CreateFullDatabaseClientMock()
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True)
Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict)
' Simulate Elfie throwing when trying to make a database from the contents of that response
factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Throws(New NotImplementedException())
' Because the parsing failed we will expect to call into the 'UpdateFailedDelay' to
' control when we do our next loop.
' Cancel processing at that point so the test can complete.
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback(
AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=factoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
factoryMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function SuccessParsingDBWritesToDisk() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simulate the local database not being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Create a client that will download the latest database.
Dim clientMock = CreateFullDatabaseClientMock()
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True)
' Successfully create a database from that response.
Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict)
factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=factoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
factoryMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function WriteAgainOnIOFailure() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simulate the database being missing.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False)
' Create a client that will download the latest databsae
Dim clientMock = CreateFullDatabaseClientMock()
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True)
' Create a database from the client response.
Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict)
factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
' Write the temp file out to disk.
ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsAny(Of String), It.IsAny(Of Byte())))
' Simulate a failure doing the first 'replace' of the database file.
ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean))).
Throws(New IOException())
' We'll expect to have to replay the write. So we should get a call to 'FileWriteDelay'
delayMock.SetupGet(Function(s) s.FileWriteDelay).Returns(TimeSpan.Zero)
' Succeed on the second write attempt.
ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean)))
' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=factoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
factoryMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_UpToDate_DoesNothing() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch that says things are up to date.
Dim clientMock = CreatePatchClientMock(isUpToDate:=True)
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
' Because everything is up to date, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_IsTooOldCausesFullDownload() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch that says things are too old.
Dim clientMock = CreatePatchClientMock(isTooOld:=True)
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
' This should cause us to want to then download the full db. So now
' setup an expectation that we'll download the latest.
Dim clientMock2 = CreateFullDatabaseClientMock()
SetupDownloadLatest(remoteControlMock, clientMock2)
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
' Because we got the full database, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
clientMock2.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_FailureToPatchCausesFullDownload() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch with contents.
Dim clientMock = CreatePatchClientMock(contents:="")
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
' Simulate a crash in the patching process.
Dim patchService = New Mock(Of IPatchService)(MockBehavior.Strict)
patchService.Setup(Sub(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))).
Throws(New NotImplementedException())
' This should cause us to want to then download the full db. So now
' setup an expectation that we'll download the latest.
Dim clientMock2 = CreateFullDatabaseClientMock()
SetupDownloadLatest(remoteControlMock, clientMock2)
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=Nothing,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
clientMock2.Verify()
patchService.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Using
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Packaging)>
Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_SuccessfulPatchWritesToDisk() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync("")
Dim cancellationTokenSource = New CancellationTokenSource()
Dim ioMock = New Mock(Of IIOService)()
' Simulate the database being there.
ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True)
' We'll successfully read in the local database.
Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict)
databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))).
Returns(New AddReferenceDatabase())
' Create a client that will return a patch with contents.
Dim clientMock = CreatePatchClientMock(contents:="")
Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False)
' Simulate a crash in the patching process.
Dim patchMock = New Mock(Of IPatchService)(MockBehavior.Strict)
patchMock.Setup(Function(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))).
Returns(New Byte() {0})
' Expect that we'll write the database to disk successfully.
SetupWritesDatabaseSuccessfullyToDisk(ioMock)
Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict)
' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'.
' Cancel processing at that point so the test can complete.
delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero).
Callback(AddressOf cancellationTokenSource.Cancel)
Dim searchService = New SymbolSearchService(
workspace,
installerService:=TestInstallerService.Instance,
remoteControlService:=remoteControlMock.Object,
logService:=TestLogService.Instance,
delayService:=delayMock.Object,
ioService:=ioMock.Object,
patchService:=patchMock.Object,
databaseFactoryService:=databaseFactoryMock.Object,
localSettingsDirectory:="TestDirectory",
reportAndSwallowException:=s_allButMoqExceptions,
cancellationTokenSource:=cancellationTokenSource)
Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource)
ioMock.Verify()
remoteControlMock.Verify()
clientMock.Verify()
patchMock.Verify()
delayMock.Verify()
databaseFactoryMock.Verify()
End Using
End Function
Private Shared Sub SetupWritesDatabaseSuccessfullyToDisk(ioMock As Mock(Of IIOService))
' Expect that we'll write out the temp file.
ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsRegex(".*tmp"), It.IsAny(Of Byte())))
' Expect that we'll replace the existing file with the temp file.
ioMock.Setup(Sub(s) s.Replace(It.IsRegex(".*tmp"), It.IsRegex(".*txt"), Nothing, It.IsAny(Of Boolean)))
End Sub
Private Shared Function CreateRemoteControlServiceMock(
clientMock As Mock(Of IRemoteControlClient),
latest As Boolean) As Mock(Of IRemoteControlService)
Dim remoteControlMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict)
If latest Then
SetupDownloadLatest(remoteControlMock, clientMock)
Else
SetupDownloadPatch(clientMock, remoteControlMock)
End If
Return remoteControlMock
End Function
Private Shared Sub SetupDownloadPatch(clientMock As Mock(Of IRemoteControlClient), remoteControlMock As Mock(Of IRemoteControlService))
remoteControlMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Patch.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object)
End Sub
Private Shared Sub SetupDownloadLatest(remoteControlMock As Mock(Of IRemoteControlService), clientMock As Mock(Of IRemoteControlClient))
remoteControlMock.Setup(
Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))).
Returns(clientMock.Object)
End Sub
Private Function CreateFullDatabaseClientMock() As Mock(Of IRemoteControlClient)
Return CreateClientMock(CreateFullDownloadElementStream())
End Function
Private Function CreateClientMock(stream As Stream) As Mock(Of IRemoteControlClient)
Dim clientMock = New Mock(Of IRemoteControlClient)(MockBehavior.Strict)
' Return a full database element when the service asks for it.
clientMock.Setup(Function(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))).
Returns(Task.FromResult(stream))
' Always dispose the client when we get a response.
clientMock.Setup(Sub(c) c.Dispose())
Return clientMock
End Function
Private Function CreatePatchClientMock(Optional isUpToDate As Boolean = False,
Optional isTooOld As Boolean = False,
Optional contents As String = Nothing) As Mock(Of IRemoteControlClient)
Return CreateClientMock(CreatePatchElementStream(isUpToDate, isTooOld, contents))
End Function
Private Function CreatePatchElementStream(Optional isUpToDate As Boolean = False,
Optional isTooOld As Boolean = False,
Optional contents As String = Nothing) As Stream
Dim element = New XElement("Patch",
If(isUpToDate, New XAttribute(SymbolSearchService.UpToDateAttributeName, True), Nothing),
If(isTooOld, New XAttribute(SymbolSearchService.TooOldAttributeName, True), Nothing),
If(contents IsNot Nothing, New XAttribute(SymbolSearchService.ContentAttributeName, contents), Nothing))
Return CreateStream(element)
End Function
Private Function CreateFullDownloadElementStream() As Stream
Dim saveStream = New MemoryStream()
Dim zipStream = New DeflateStream(saveStream, CompressionMode.Compress)
zipStream.Write(New Byte() {0}, 0, 1)
zipStream.Flush()
Dim contents = Convert.ToBase64String(saveStream.ToArray())
Return CreateStream(New XElement("Database",
New XAttribute(SymbolSearchService.ContentAttributeName, contents)))
End Function
Private Function CreateStream(element As XElement) As Stream
Dim stream = New MemoryStream()
element.Save(stream)
stream.Position = 0
Return stream
End Function
Private Class TestDelayService
Implements IDelayService
Public Shared ReadOnly Instance As TestDelayService = New TestDelayService()
Private Sub New()
End Sub
Public ReadOnly Property CachePollDelay As TimeSpan Implements IDelayService.CachePollDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property FileWriteDelay As TimeSpan Implements IDelayService.FileWriteDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property ExpectedFailureDelay As TimeSpan Implements IDelayService.ExpectedFailureDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property UpdateSucceededDelay As TimeSpan Implements IDelayService.UpdateSucceededDelay
Get
Return TimeSpan.Zero
End Get
End Property
Public ReadOnly Property CatastrophicFailureDelay As TimeSpan Implements IDelayService.CatastrophicFailureDelay
Get
Return TimeSpan.Zero
End Get
End Property
End Class
Private Class TestInstallerService
Implements IPackageInstallerService
Public Shared ReadOnly Instance As IPackageInstallerService = New TestInstallerService()
Public ReadOnly Property IsEnabled As Boolean Implements IPackageInstallerService.IsEnabled
Get
Return True
End Get
End Property
Public ReadOnly Property PackageSources As ImmutableArray(Of PackageSource) Implements IPackageInstallerService.PackageSources
Get
Throw New NotImplementedException()
End Get
End Property
Public Event PackageSourcesChanged As EventHandler Implements IPackageInstallerService.PackageSourcesChanged
Public Sub ShowManagePackagesDialog(packageName As String) Implements IPackageInstallerService.ShowManagePackagesDialog
Throw New NotImplementedException()
End Sub
Public Iterator Function GetInstalledVersions(packageName As String) As IEnumerable(Of String) Implements IPackageInstallerService.GetInstalledVersions
End Function
Public Function GetProjectsWithInstalledPackage(solution As Solution, packageName As String, version As String) As IEnumerable(Of Project) Implements IPackageInstallerService.GetProjectsWithInstalledPackage
Throw New NotImplementedException()
End Function
Public Function IsInstalled(workspace As Workspace, projectId As ProjectId, packageName As String) As Boolean Implements IPackageInstallerService.IsInstalled
Throw New NotImplementedException()
End Function
Public Function TryInstallPackage(workspace As Workspace, documentId As DocumentId, source As String, packageName As String, versionOpt As String, cancellationToken As CancellationToken) As Boolean Implements IPackageInstallerService.TryInstallPackage
Throw New NotImplementedException()
End Function
End Class
Private Class TestLogService
Implements ILogService
Public Shared ReadOnly Instance As TestLogService = New TestLogService()
Private Sub New()
End Sub
Public Sub LogException(e As Exception, text As String) Implements ILogService.LogException
End Sub
Public Sub LogInfo(text As String) Implements ILogService.LogInfo
End Sub
End Class
End Class
End Namespace
\ No newline at end of file
......@@ -226,6 +226,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Import Directives.
'''</summary>
Friend Shared ReadOnly Property Option_Import_Directives() As String
Get
Return ResourceManager.GetString("Option_Import_Directives", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to _Navigate to Object Browser for symbols defined in metadata.
'''</summary>
......@@ -290,7 +299,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Property
'''<summary>
''' Looks up a localized string similar to Show preview for _rename tracking.
''' Looks up a localized string similar to _Place &apos;System&apos; directives first when sorting imports.
'''</summary>
Friend Shared ReadOnly Property Option_PlaceSystemNamespaceFirst() As String
Get
Return ResourceManager.GetString("Option_PlaceSystemNamespaceFirst", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Show preview for rename _tracking.
'''</summary>
Friend Shared ReadOnly Property Option_RenameTrackingPreview() As String
Get
......@@ -298,6 +316,24 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Suggest imports for types in _NuGet packages.
'''</summary>
Friend Shared ReadOnly Property Option_Suggest_imports_for_types_in_NuGet_packages() As String
Get
Return ResourceManager.GetString("Option_Suggest_imports_for_types_in_NuGet_packages", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Suggest imports for types in _reference assemblies.
'''</summary>
Friend Shared ReadOnly Property Option_Suggest_imports_for_types_in_reference_assemblies() As String
Get
Return ResourceManager.GetString("Option_Suggest_imports_for_types_in_reference_assemblies", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Prefer intrinsic predefined type keyword when declaring locals, parameters and members.
'''</summary>
......
......@@ -196,7 +196,7 @@
<value>Performance</value>
</data>
<data name="Option_RenameTrackingPreview" xml:space="preserve">
<value>Show preview for _rename tracking</value>
<value>Show preview for rename _tracking</value>
</data>
<data name="Option_NavigateToObjectBrowser" xml:space="preserve">
<value>_Navigate to Object Browser for symbols defined in metadata</value>
......@@ -204,4 +204,16 @@
<data name="Option_GoToDefinition" xml:space="preserve">
<value>Go to Definition</value>
</data>
<data name="Option_Import_Directives" xml:space="preserve">
<value>Import Directives</value>
</data>
<data name="Option_Suggest_imports_for_types_in_NuGet_packages" xml:space="preserve">
<value>Suggest imports for types in _NuGet packages</value>
</data>
<data name="Option_Suggest_imports_for_types_in_reference_assemblies" xml:space="preserve">
<value>Suggest imports for types in _reference assemblies</value>
</data>
<data name="Option_PlaceSystemNamespaceFirst" xml:space="preserve">
<value>_Place 'System' directives first when sorting imports</value>
</data>
</root>
\ No newline at end of file
......@@ -11,6 +11,21 @@
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<GroupBox x:Uid="ImportDirectivesGroupBox"
Header="{x:Static local:AdvancedOptionPageStrings.Option_Import_Directives}">
<StackPanel>
<CheckBox x:Name="PlaceSystemNamespaceFirst"
x:Uid="SortImports_PlaceSystemFirst"
Content="{x:Static local:AdvancedOptionPageStrings.Option_PlaceSystemNamespaceFirst}" />
<CheckBox x:Name="SuggestForTypesInReferenceAssemblies"
x:Uid="AddImport_SuggestForTypesInReferenceAssemblies"
Content="{x:Static local:AdvancedOptionPageStrings.Option_Suggest_imports_for_types_in_reference_assemblies}" />
<CheckBox x:Name="SuggestForTypesInNuGetPackages"
x:Uid="AddImport_SuggestForTypesInNuGetPackages"
Content="{x:Static local:AdvancedOptionPageStrings.Option_Suggest_imports_for_types_in_NuGet_packages}" />
</StackPanel>
</GroupBox>
<GroupBox x:Uid="HighlightingGroupBox"
Header="{x:Static local:AdvancedOptionPageStrings.Option_Highlighting}">
<StackPanel>
......
......@@ -13,6 +13,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
InitializeComponent()
BindToOption(PlaceSystemNamespaceFirst, OrganizerOptions.PlaceSystemNamespaceFirst, LanguageNames.VisualBasic)
BindToOption(SuggestForTypesInReferenceAssemblies, AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic)
BindToOption(SuggestForTypesInNuGetPackages, AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic)
BindToOption(EnableEndConstruct, FeatureOnOffOptions.EndConstruct, LanguageNames.VisualBasic)
BindToOption(EnableOutlining, FeatureOnOffOptions.Outlining, LanguageNames.VisualBasic)
BindToOption(EnableLineCommit, FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic)
......
......@@ -141,5 +141,28 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
End Get
End Property
Public ReadOnly Property Option_Import_Directives As String
Get
Return BasicVSResources.Option_Import_Directives
End Get
End Property
Public ReadOnly Property Option_PlaceSystemNamespaceFirst As String
Get
Return BasicVSResources.Option_PlaceSystemNamespaceFirst
End Get
End Property
Public ReadOnly Property Option_Suggest_imports_for_types_in_reference_assemblies As String
Get
Return BasicVSResources.Option_Suggest_imports_for_types_in_reference_assemblies
End Get
End Property
Public ReadOnly Property Option_Suggest_imports_for_types_in_NuGet_packages As String
Get
Return BasicVSResources.Option_Suggest_imports_for_types_in_NuGet_packages
End Get
End Property
End Module
End Namespace
End Namespace
\ No newline at end of file
......@@ -166,6 +166,33 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
End Set
End Property
Public Property Option_PlaceSystemNamespaceFirst As Boolean
Get
Return GetBooleanOption(OrganizerOptions.PlaceSystemNamespaceFirst)
End Get
Set(value As Boolean)
SetBooleanOption(OrganizerOptions.PlaceSystemNamespaceFirst, value)
End Set
End Property
Public Property Option_Suggest_imports_for_types_in_reference_assemblies As Boolean
Get
Return GetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies)
End Get
Set(value As Boolean)
SetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, value)
End Set
End Property
Public Property Option_Suggest_imports_for_types_in_NuGet_packages As Boolean
Get
Return GetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages)
End Get
Set(value As Boolean)
SetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages, value)
End Set
End Property
Private Function GetBooleanOption(key As [Option](Of Boolean)) As Boolean
Return _optionService.GetOption(key)
End Function
......
......@@ -8,9 +8,16 @@ Imports Microsoft.VisualStudio.Shell
Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options
Imports Microsoft.CodeAnalysis.Options
Imports System.Composition
Imports Microsoft.CodeAnalysis.Shared.Options
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
<ExportLanguageSpecificOptionSerializer(LanguageNames.VisualBasic, FormattingOptions.TabFeatureName, BraceCompletionOptions.FeatureName, CompletionOptions.FeatureName, SignatureHelpOptions.FeatureName, NavigationBarOptions.FeatureName), [Shared]>
<ExportLanguageSpecificOptionSerializer(
LanguageNames.VisualBasic,
FormattingOptions.TabFeatureName,
BraceCompletionOptions.FeatureName,
CompletionOptions.FeatureName,
SignatureHelpOptions.FeatureName,
NavigationBarOptions.FeatureName), [Shared]>
Friend NotInheritable Class VisualBasicLanguageSettingsSerializer
Inherits AbstractLanguageSettingsSerializer
......
......@@ -17,6 +17,7 @@ Imports Microsoft.VisualStudio.Shell
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
<ExportLanguageSpecificOptionSerializer(
LanguageNames.VisualBasic,
AddImportOptions.FeatureName,
SimplificationOptions.PerLanguageFeatureName,
ExtractMethodOptions.FeatureName,
FeatureOnOffOptions.OptionName,
......@@ -46,6 +47,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "AutoRequiredMemberInsert", FeatureOnOffOptions.AutomaticInsertionOfAbstractOrInterfaceMembers)})
Dim Types As Type() = {
GetType(AddImportOptions),
GetType(FormattingOptions),
GetType(ExtractMethodOptions),
GetType(SimplificationOptions),
......@@ -85,6 +87,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
End If
Return [option].Feature = FormattingOptions.InternalTabFeatureName Or
[option].Feature = AddImportOptions.FeatureName Or
[option].Feature = ExtractMethodOptions.FeatureName Or
[option].Feature = SimplificationOptions.PerLanguageFeatureName Or
[option].Feature = ServiceFeatureOnOffOptions.OptionName Or
......
using System.Collections.Generic;
using System.Threading;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Packaging
{
internal interface IReferenceAssemblySearchService : IWorkspaceService
{
/// <summary>
/// Searches for reference assemblies that contain a type with the provided name and arity.
/// Note: Implementations are free to return the results they feel best for the
/// given data. Specifically, they can do exact or fuzzy matching on the name.
/// They can use or ignore the arity depending on their capabilities.
///
/// Implementations should return results in order from best to worst (from their
/// perspective).
/// </summary>
IEnumerable<ReferenceAssemblyWithTypeResult> FindReferenceAssembliesWithType(
string name, int arity, CancellationToken cancellationToken);
}
internal class ReferenceAssemblyWithTypeResult
{
public readonly IReadOnlyList<string> ContainingNamespaceNames;
public readonly string AssemblyName;
public readonly string TypeName;
public ReferenceAssemblyWithTypeResult(
string assemblyName,
string typeName,
IReadOnlyList<string> containingNamespaceNames)
{
AssemblyName = assemblyName;
TypeName = typeName;
ContainingNamespaceNames = containingNamespaceNames;
}
}
}
......@@ -4,9 +4,9 @@
using System.Threading;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Packaging
namespace Microsoft.CodeAnalysis.SymbolSearch
{
internal interface IPackageSearchService : IWorkspaceService
internal interface ISymbolSearchService : IWorkspaceService
{
/// <summary>
/// Searches for packages that contain a type with the provided name and arity.
......@@ -19,6 +19,18 @@ internal interface IPackageSearchService : IWorkspaceService
/// </summary>
IEnumerable<PackageWithTypeResult> FindPackagesWithType(
string source, string name, int arity, CancellationToken cancellationToken);
/// <summary>
/// Searches for reference assemblies that contain a type with the provided name and arity.
/// Note: Implementations are free to return the results they feel best for the
/// given data. Specifically, they can do exact or fuzzy matching on the name.
/// They can use or ignore the arity depending on their capabilities.
///
/// Implementations should return results in order from best to worst (from their
/// perspective).
/// </summary>
IEnumerable<ReferenceAssemblyWithTypeResult> FindReferenceAssembliesWithType(
string name, int arity, CancellationToken cancellationToken);
}
internal class PackageWithTypeResult
......@@ -40,4 +52,21 @@ internal class PackageWithTypeResult
ContainingNamespaceNames = containingNamespaceNames;
}
}
internal class ReferenceAssemblyWithTypeResult
{
public readonly IReadOnlyList<string> ContainingNamespaceNames;
public readonly string AssemblyName;
public readonly string TypeName;
public ReferenceAssemblyWithTypeResult(
string assemblyName,
string typeName,
IReadOnlyList<string> containingNamespaceNames)
{
AssemblyName = assemblyName;
TypeName = typeName;
ContainingNamespaceNames = containingNamespaceNames;
}
}
}
......@@ -396,12 +396,11 @@
<Compile Include="FindSymbols\FindReferences\Finders\ILanguageServiceReferenceFinder.cs" />
<Compile Include="LinkedFileDiffMerging\LinkedFileDiffMergingLogger.cs" />
<Compile Include="Packaging\IPackageInstallerService.cs" />
<Compile Include="Packaging\IPackageSearchService.cs" />
<Compile Include="SymbolSearch\ISymbolSearchService.cs" />
<Compile Include="FindSymbols\SymbolTree\ISymbolTreeInfoCacheService.cs" />
<Compile Include="FindSymbols\FindReferences\MetadataUnifyingEquivalenceComparer.cs" />
<Compile Include="SymbolId\SymbolId.cs" />
<Compile Include="Shared\Utilities\IProgressTracker.cs" />
<Compile Include="Packaging\IReferenceAssemblySearchService.cs" />
<Compile Include="Utilities\ArraySlice.cs" />
<Compile Include="Utilities\BKTree.cs" />
<Compile Include="FindSymbols\SyntaxTree\AbstractSyntaxTreeInfo.cs" />
......@@ -983,4 +982,4 @@
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册