未验证 提交 535127a6 编写于 作者: J Jason Malinowski 提交者: GitHub

Merge pull request #35745 from dotnet/release/dev16.1

Merge dev16.1 into dev16.2-preview1-vs-deps
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
......@@ -40,10 +41,10 @@ public bool TryGetDocumentOption(OptionKey option, OptionSet underlyingOptions,
// Dictionary<string, object> from the old system.
//
// We cache this with a conditional weak table so we're able to maintain the assumptions in EditorConfigNamingStyleParser
// that the instance doesn't regularly change and thus can be used for further caching
// that the instance doesn't regularly change and thus can be used for further caching.
var allRawConventions = s_convertedDictionaryCache.GetValue(
_codingConventionSnapshot.AllRawConventions,
d => ImmutableDictionary.CreateRange(d.Select(c => KeyValuePairUtil.Create(c.Key, c.Value.ToString()))));
d => new StringConvertingDictionary(d));
try
{
......@@ -57,6 +58,57 @@ public bool TryGetDocumentOption(OptionKey option, OptionSet underlyingOptions,
return false;
}
}
/// <summary>
/// A class that implements <see cref="IReadOnlyDictionary{String, String}" /> atop a <see cref="IReadOnlyDictionary{String, Object}" />
/// where we just convert the values to strings with ToString(). Ordering of the underlying dictionary is preserved, so that way
/// code that relies on the underlying ordering of the underlying dictionary isn't affected.
/// </summary>
private class StringConvertingDictionary : IReadOnlyDictionary<string, string>
{
private readonly IReadOnlyDictionary<string, object> _underlyingDictionary;
public StringConvertingDictionary(IReadOnlyDictionary<string, object> underlyingDictionary)
{
_underlyingDictionary = underlyingDictionary ?? throw new ArgumentNullException(nameof(underlyingDictionary));
}
public string this[string key] => _underlyingDictionary[key]?.ToString();
public IEnumerable<string> Keys => _underlyingDictionary.Keys;
public IEnumerable<string> Values => _underlyingDictionary.Values.Select(s => s?.ToString());
public int Count => _underlyingDictionary.Count;
public bool ContainsKey(string key) => _underlyingDictionary.ContainsKey(key);
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
foreach (var pair in _underlyingDictionary)
{
yield return new KeyValuePair<string, string>(pair.Key, pair.Value?.ToString());
}
}
public bool TryGetValue(string key, out string value)
{
if (_underlyingDictionary.TryGetValue(key, out object objectValue))
{
value = objectValue?.ToString();
return true;
}
else
{
value = null;
return false;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.Editor.Options;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.CodingConventions;
using Microsoft.VisualStudio.Composition;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests.EditorConfigStorageLocation
{
[UseExportProvider]
public class LegacyEditorConfigDocumentOptionsProviderTests
{
[Fact]
public void OrderingOfEditorConfigMaintained()
{
using var tempRoot = new TempRoot();
var tempDirectory = tempRoot.CreateDirectory();
// Write out an .editorconfig. We'll write out 100 random GUIDs
var expectedKeysInOrder = new List<string>();
using (var writer = new StreamWriter(tempDirectory.CreateFile(".editorconfig").Path))
{
writer.WriteLine("root = true");
writer.WriteLine("[*.cs]");
for (int i = 0; i < 100; i++)
{
var key = Guid.NewGuid().ToString();
expectedKeysInOrder.Add(key);
writer.WriteLine($"{key} = value");
}
}
// Create a workspace with a file in that path
var codingConventionsCatalog = ExportProviderCache.GetOrCreateAssemblyCatalog(typeof(ICodingConventionsManager).Assembly).WithPart(typeof(MockFileWatcher));
var exportProvider = ExportProviderCache.GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(codingConventionsCatalog)).CreateExportProvider();
using var workspace = TestWorkspace.CreateWorkspace(
new XElement("Workspace",
new XElement("Project", new XAttribute("Language", "C#"),
new XElement("Document", new XAttribute("FilePath", tempDirectory.CreateFile("Test.cs").Path)))), exportProvider: exportProvider);
var document = workspace.CurrentSolution.Projects.Single().Documents.Single();
var providerFactory = workspace.ExportProvider.GetExportedValues<IDocumentOptionsProviderFactory>().OfType<LegacyEditorConfigDocumentOptionsProviderFactory>().Single();
var provider = providerFactory.TryCreate(workspace);
var option = new Option<List<string>>(nameof(LegacyEditorConfigDocumentOptionsProviderTests), nameof(OrderingOfEditorConfigMaintained), null, new[] { new KeysReturningStorageLocation() });
var optionKey = new OptionKey(option);
// Fetch the underlying option order with a "option" that returns the keys
provider.GetOptionsForDocumentAsync(document, CancellationToken.None).Result.TryGetDocumentOption(optionKey, workspace.Options, out object actualKeysInOrderObject);
var actualKeysInOrder = Assert.IsAssignableFrom<IEnumerable<string>>(actualKeysInOrderObject);
Assert.Equal(expectedKeysInOrder, actualKeysInOrder);
}
[PartNotDiscoverable]
[Export(typeof(IFileWatcher))]
[Shared]
private class MockFileWatcher : IFileWatcher
{
#pragma warning disable CS0067 // the event is unused
public event ConventionsFileChangedAsyncEventHandler ConventionFileChanged;
public event ContextFileMovedAsyncEventHandler ContextFileMoved;
#pragma warning restore CS0067
public void Dispose()
{
}
public void StartWatching(string fileName, string directoryPath)
{
}
public void StopWatching(string fileName, string directoryPath)
{
}
}
/// <summary>
/// An option storage location that returns as the value all the keys in the order they came from the underlying storage.
/// </summary>
private class KeysReturningStorageLocation : OptionStorageLocation, IEditorConfigStorageLocation
{
public bool TryGetOption(object underlyingOption, IReadOnlyDictionary<string, string> rawOptions, Type type, out object value)
{
value = rawOptions.Keys;
return true;
}
}
}
}
......@@ -55,6 +55,7 @@
<Reference Include="System.Xml.Linq" />
<Reference Include="WindowsBase" />
<PackageReference Include="BasicUndo" Version="$(BasicUndoVersion)" />
<PackageReference Include="Microsoft.VisualStudio.CodingConventions" Version="$(MicrosoftVisualStudioCodingConventionsVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Composition" Version="$(MicrosoftVisualStudioCompositionVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Platform.VSEditor" Version="$(MicrosoftVisualStudioPlatformVSEditorVersion)" />
<PackageReference Include="Microsoft.VisualStudio.InteractiveWindow" Version="$(MicrosoftVisualStudioInteractiveWindowVersion)" />
......
......@@ -11,7 +11,7 @@
namespace Microsoft.CodeAnalysis.UnitTests.EditorConfig.StorageLocation
{
public class EditorConfigStorageLocationTests
public class NamingStylePreferenceEditorConfigStorageLocationTests
{
[Fact]
public static void TestEmptyDictionaryReturnNoNamingStylePreferencesObjectReturnsFalse()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册