Add host project system for VS4Mac.
- Tied into VS4Macs ProjectExtensions in order to bootstrap our Razor world. - We currently watch all DotNet projects with the expectation that they're the only ones that can potentially turn into Razor compatible projects. - Added a fallback Razor project host which is used for pre-Razor SDK Razor versions (< 2.1). - Added a default Razor project host which consumes all MSBuild data from the users packages and sets up the Razor world accordingly. - Had to modify some existing contracts to work better with new expectations. one of these was the VS4Mac specific Workspace accessor; essentially we needed to be able to lookup a workspace from a solution. - Some of our previous expectations about addins were wrong (not being able to directly reference your libraries). To avoid using reflection to bootstrap our types I tried out directly referencing our libraries and all worked fine. - Refactored the DefaultRazorProjectHost in windows (since we had to in Mac) for testing purposes. #2081
This commit is contained in:
parent
492e958114
commit
1d602d1205
|
|
@ -36,7 +36,7 @@
|
||||||
<MicrosoftVisualStudioShellInterop90PackageVersion>9.0.30729</MicrosoftVisualStudioShellInterop90PackageVersion>
|
<MicrosoftVisualStudioShellInterop90PackageVersion>9.0.30729</MicrosoftVisualStudioShellInterop90PackageVersion>
|
||||||
<MicrosoftVisualStudioShellInteropPackageVersion>7.10.6071</MicrosoftVisualStudioShellInteropPackageVersion>
|
<MicrosoftVisualStudioShellInteropPackageVersion>7.10.6071</MicrosoftVisualStudioShellInteropPackageVersion>
|
||||||
<MicrosoftVisualStudioTextUIPackageVersion>15.6.161-preview</MicrosoftVisualStudioTextUIPackageVersion>
|
<MicrosoftVisualStudioTextUIPackageVersion>15.6.161-preview</MicrosoftVisualStudioTextUIPackageVersion>
|
||||||
<MonoAddinsPackageVersion>1.3.7</MonoAddinsPackageVersion>
|
<MonoAddinsPackageVersion>1.3.8</MonoAddinsPackageVersion>
|
||||||
<MonoDevelopSdkPackageVersion>1.0.1</MonoDevelopSdkPackageVersion>
|
<MonoDevelopSdkPackageVersion>1.0.1</MonoDevelopSdkPackageVersion>
|
||||||
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
||||||
<NETStandardLibrary20PackageVersion>2.0.1</NETStandardLibrary20PackageVersion>
|
<NETStandardLibrary20PackageVersion>2.0.1</NETStandardLibrary20PackageVersion>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
|
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Mac.RazorAddin, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -10,6 +12,9 @@ using System.Threading.Tasks.Dataflow;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.VisualStudio.LanguageServices;
|
using Microsoft.VisualStudio.LanguageServices;
|
||||||
using Microsoft.VisualStudio.ProjectSystem;
|
using Microsoft.VisualStudio.ProjectSystem;
|
||||||
|
using Microsoft.VisualStudio.ProjectSystem.Properties;
|
||||||
|
using ProjectState = System.Collections.Immutable.IImmutableDictionary<string, Microsoft.VisualStudio.ProjectSystem.Properties.IProjectRuleSnapshot>;
|
||||||
|
using ProjectStateItem = System.Collections.Generic.KeyValuePair<string, System.Collections.Immutable.IImmutableDictionary<string, string>>;
|
||||||
|
|
||||||
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
{
|
{
|
||||||
|
|
@ -82,47 +87,180 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
{
|
{
|
||||||
await ExecuteWithLock(async () =>
|
await ExecuteWithLock(async () =>
|
||||||
{
|
{
|
||||||
var languageVersion = update.Value.CurrentState[Rules.RazorGeneral.SchemaName].Properties[Rules.RazorGeneral.RazorLangVersionProperty];
|
if (TryGetConfiguration(update.Value.CurrentState, out var configuration))
|
||||||
var defaultConfiguration = update.Value.CurrentState[Rules.RazorGeneral.SchemaName].Properties[Rules.RazorGeneral.RazorDefaultConfigurationProperty];
|
|
||||||
|
|
||||||
RazorConfiguration configuration = null;
|
|
||||||
if (!string.IsNullOrEmpty(languageVersion) && !string.IsNullOrEmpty(defaultConfiguration))
|
|
||||||
{
|
{
|
||||||
if (!RazorLanguageVersion.TryParse(languageVersion, out var parsedVersion))
|
var hostProject = new HostProject(CommonServices.UnconfiguredProject.FullPath, configuration);
|
||||||
{
|
await UpdateProjectUnsafeAsync(hostProject).ConfigureAwait(false);
|
||||||
parsedVersion = RazorLanguageVersion.Latest;
|
|
||||||
}
|
|
||||||
|
|
||||||
var extensions = update.Value.CurrentState[Rules.RazorExtension.PrimaryDataSourceItemType].Items.Select(e =>
|
|
||||||
{
|
|
||||||
return new ProjectSystemRazorExtension(e.Key);
|
|
||||||
}).ToArray();
|
|
||||||
|
|
||||||
var configurations = update.Value.CurrentState[Rules.RazorConfiguration.PrimaryDataSourceItemType].Items.Select(c =>
|
|
||||||
{
|
|
||||||
var includedExtensions = c.Value[Rules.RazorConfiguration.ExtensionsProperty]
|
|
||||||
.Split(';')
|
|
||||||
.Select(name => extensions.Where(e => e.ExtensionName == name).FirstOrDefault())
|
|
||||||
.Where(e => e != null)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return new ProjectSystemRazorConfiguration(parsedVersion, c.Key, includedExtensions);
|
|
||||||
}).ToArray();
|
|
||||||
|
|
||||||
configuration = configurations.Where(c => c.ConfigurationName == defaultConfiguration).FirstOrDefault();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (configuration == null)
|
|
||||||
{
|
{
|
||||||
// Ok we can't find a language version. Let's assume this project isn't using Razor then.
|
// Ok we can't find a configuration. Let's assume this project isn't using Razor then.
|
||||||
await UpdateProjectUnsafeAsync(null).ConfigureAwait(false);
|
await UpdateProjectUnsafeAsync(null).ConfigureAwait(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostProject = new HostProject(CommonServices.UnconfiguredProject.FullPath, configuration);
|
|
||||||
await UpdateProjectUnsafeAsync(hostProject).ConfigureAwait(false);
|
|
||||||
});
|
});
|
||||||
}, registerFaultHandler: true);
|
}, registerFaultHandler: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetConfiguration(
|
||||||
|
ProjectState projectState,
|
||||||
|
out RazorConfiguration configuration)
|
||||||
|
{
|
||||||
|
if (!TryGetDefaultConfiguration(projectState, out var defaultConfiguration))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetLanguageVersion(projectState, out var languageVersion))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetConfigurationItem(defaultConfiguration, projectState, out var configurationItem))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetExtensions(configuredExtensionNames, projectState, out var extensions))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration = new ProjectSystemRazorConfiguration(languageVersion, configurationItem.Key, extensions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetDefaultConfiguration(ProjectState projectState, out string defaultConfiguration)
|
||||||
|
{
|
||||||
|
if (!projectState.TryGetValue(Rules.RazorGeneral.SchemaName, out var rule))
|
||||||
|
{
|
||||||
|
defaultConfiguration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rule.Properties.TryGetValue(Rules.RazorGeneral.RazorDefaultConfigurationProperty, out defaultConfiguration))
|
||||||
|
{
|
||||||
|
defaultConfiguration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(defaultConfiguration))
|
||||||
|
{
|
||||||
|
defaultConfiguration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetLanguageVersion(ProjectState projectState, out RazorLanguageVersion languageVersion)
|
||||||
|
{
|
||||||
|
if (!projectState.TryGetValue(Rules.RazorGeneral.SchemaName, out var rule))
|
||||||
|
{
|
||||||
|
languageVersion = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rule.Properties.TryGetValue(Rules.RazorGeneral.RazorLangVersionProperty, out var languageVersionValue))
|
||||||
|
{
|
||||||
|
languageVersion = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(languageVersionValue))
|
||||||
|
{
|
||||||
|
languageVersion = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RazorLanguageVersion.TryParse(languageVersionValue, out languageVersion))
|
||||||
|
{
|
||||||
|
languageVersion = RazorLanguageVersion.Latest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetConfigurationItem(
|
||||||
|
string configuration,
|
||||||
|
ProjectState projectState,
|
||||||
|
out ProjectStateItem configurationItem)
|
||||||
|
{
|
||||||
|
if (!projectState.TryGetValue(Rules.RazorConfiguration.PrimaryDataSourceItemType, out var configurationState))
|
||||||
|
{
|
||||||
|
configurationItem = default(ProjectStateItem);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var razorConfigurationItems = configurationState.Items;
|
||||||
|
foreach (var item in razorConfigurationItems)
|
||||||
|
{
|
||||||
|
if (item.Key == configuration)
|
||||||
|
{
|
||||||
|
configurationItem = item;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurationItem = default(ProjectStateItem);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetConfiguredExtensionNames(ProjectStateItem configurationItem, out string[] configuredExtensionNames)
|
||||||
|
{
|
||||||
|
if (!configurationItem.Value.TryGetValue(Rules.RazorConfiguration.ExtensionsProperty, out var extensionNamesValue))
|
||||||
|
{
|
||||||
|
configuredExtensionNames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(extensionNamesValue))
|
||||||
|
{
|
||||||
|
configuredExtensionNames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
configuredExtensionNames = extensionNamesValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetExtensions(string[] configuredExtensionNames, ProjectState projectState, out ProjectSystemRazorExtension[] extensions)
|
||||||
|
{
|
||||||
|
if (!projectState.TryGetValue(Rules.RazorExtension.PrimaryDataSourceItemType, out var extensionState))
|
||||||
|
{
|
||||||
|
extensions = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var extensionItems = extensionState.Items;
|
||||||
|
var extensionList = new List<ProjectSystemRazorExtension>();
|
||||||
|
foreach (var item in extensionItems)
|
||||||
|
{
|
||||||
|
var extensionName = item.Key;
|
||||||
|
if (configuredExtensionNames.Contains(extensionName))
|
||||||
|
{
|
||||||
|
extensionList.Add(new ProjectSystemRazorExtension(extensionName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions = extensionList.ToArray();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,12 +13,13 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor
|
||||||
{
|
{
|
||||||
[System.Composition.Shared]
|
[System.Composition.Shared]
|
||||||
[Export(typeof(VisualStudioWorkspaceAccessor))]
|
[Export(typeof(VisualStudioWorkspaceAccessor))]
|
||||||
internal class DefaultVisualStudioWorkspaceAccessor : VisualStudioWorkspaceAccessor
|
[Export(typeof(VisualStudioMacWorkspaceAccessor))]
|
||||||
|
internal class DefaultVisualStudioMacWorkspaceAccessor : VisualStudioMacWorkspaceAccessor
|
||||||
{
|
{
|
||||||
private readonly TextBufferProjectService _projectService;
|
private readonly TextBufferProjectService _projectService;
|
||||||
|
|
||||||
[ImportingConstructor]
|
[ImportingConstructor]
|
||||||
public DefaultVisualStudioWorkspaceAccessor(TextBufferProjectService projectService)
|
public DefaultVisualStudioMacWorkspaceAccessor(TextBufferProjectService projectService)
|
||||||
{
|
{
|
||||||
if (projectService == null)
|
if (projectService == null)
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +57,17 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace = TypeSystemService.GetWorkspace(hostSolution);
|
return TryGetWorkspace(hostSolution, out workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool TryGetWorkspace(Solution solution, out Workspace workspace)
|
||||||
|
{
|
||||||
|
if (solution == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(solution));
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace = TypeSystemService.GetWorkspace(solution);
|
||||||
|
|
||||||
// Workspace cannot be null at this point. If TypeSystemService.GetWorkspace isn't able to find a corresponding
|
// Workspace cannot be null at this point. If TypeSystemService.GetWorkspace isn't able to find a corresponding
|
||||||
// workspace it returns an empty workspace. Therefore, in order to see if we have a valid workspace we need to
|
// workspace it returns an empty workspace. Therefore, in order to see if we have a valid workspace we need to
|
||||||
|
|
@ -17,6 +17,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.Editor
|
||||||
[Export(typeof(TextBufferProjectService))]
|
[Export(typeof(TextBufferProjectService))]
|
||||||
internal class DefaultTextBufferProjectService : TextBufferProjectService
|
internal class DefaultTextBufferProjectService : TextBufferProjectService
|
||||||
{
|
{
|
||||||
|
private const string DotNetCoreRazorCapability = "DotNetCoreRazor | AspNetCore";
|
||||||
private readonly ITextDocumentFactoryService _documentFactory;
|
private readonly ITextDocumentFactoryService _documentFactory;
|
||||||
|
|
||||||
[ImportingConstructor]
|
[ImportingConstructor]
|
||||||
|
|
@ -73,7 +74,20 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.Editor
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisualStudio for Mac only supports ASP.NET Core Razor.
|
// VisualStudio for Mac only supports ASP.NET Core Razor.
|
||||||
public override bool IsSupportedProject(object project) => project is DotNetProject;
|
public override bool IsSupportedProject(object project)
|
||||||
|
{
|
||||||
|
if (!(project is DotNetProject dotNetProject))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dotNetProject.IsCapabilityMatch(DotNetCoreRazorCapability))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public override string GetProjectName(object project)
|
public override string GetProjectName(object project)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
internal class DefaultDotNetProjectHost : DotNetProjectHost
|
||||||
|
{
|
||||||
|
private const string ExplicitRazorConfigurationCapability = "DotNetCoreRazorConfiguration";
|
||||||
|
|
||||||
|
private readonly DotNetProject _project;
|
||||||
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
|
private readonly VisualStudioMacWorkspaceAccessor _workspaceAccessor;
|
||||||
|
private readonly TextBufferProjectService _projectService;
|
||||||
|
private RazorProjectHostBase _razorProjectHost;
|
||||||
|
|
||||||
|
public DefaultDotNetProjectHost(
|
||||||
|
DotNetProject project,
|
||||||
|
ForegroundDispatcher foregroundDispatcher,
|
||||||
|
VisualStudioMacWorkspaceAccessor workspaceAccessor,
|
||||||
|
TextBufferProjectService projectService)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foregroundDispatcher == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(foregroundDispatcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspaceAccessor == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspaceAccessor));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectService == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectService));
|
||||||
|
}
|
||||||
|
|
||||||
|
_project = project;
|
||||||
|
_foregroundDispatcher = foregroundDispatcher;
|
||||||
|
_workspaceAccessor = workspaceAccessor;
|
||||||
|
_projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal DefaultDotNetProjectHost(
|
||||||
|
ForegroundDispatcher foregroundDispatcher,
|
||||||
|
VisualStudioMacWorkspaceAccessor workspaceAccessor,
|
||||||
|
TextBufferProjectService projectService)
|
||||||
|
{
|
||||||
|
if (foregroundDispatcher == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(foregroundDispatcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspaceAccessor == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspaceAccessor));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectService == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectService));
|
||||||
|
}
|
||||||
|
|
||||||
|
_foregroundDispatcher = foregroundDispatcher;
|
||||||
|
_workspaceAccessor = workspaceAccessor;
|
||||||
|
_projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DotNetProject Project => _project;
|
||||||
|
|
||||||
|
public override void Subscribe()
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
UpdateRazorHostProject();
|
||||||
|
|
||||||
|
_project.ProjectCapabilitiesChanged += Project_ProjectCapabilitiesChanged;
|
||||||
|
_project.Disposing += Project_Disposing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Project_Disposing(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
_project.ProjectCapabilitiesChanged -= Project_ProjectCapabilitiesChanged;
|
||||||
|
_project.Disposing -= Project_Disposing;
|
||||||
|
|
||||||
|
DetatchCurrentRazorProjectHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Project_ProjectCapabilitiesChanged(object sender, EventArgs e) => UpdateRazorHostProject();
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal void UpdateRazorHostProject()
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
DetatchCurrentRazorProjectHost();
|
||||||
|
|
||||||
|
if (!_projectService.IsSupportedProject(_project))
|
||||||
|
{
|
||||||
|
// Not a Razor compatible project.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetProjectSnapshotManager(out var projectSnapshotManager))
|
||||||
|
{
|
||||||
|
// Could not get a ProjectSnapshotManager for the current project.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_project.IsCapabilityMatch(ExplicitRazorConfigurationCapability))
|
||||||
|
{
|
||||||
|
// SDK >= 2.1
|
||||||
|
_razorProjectHost = new DefaultRazorProjectHost(_project, _foregroundDispatcher, projectSnapshotManager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're an older version of Razor at this point, SDK < 2.1
|
||||||
|
_razorProjectHost = new FallbackRazorProjectHost(_project, _foregroundDispatcher, projectSnapshotManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetProjectSnapshotManager(out ProjectSnapshotManagerBase projectSnapshotManagerBase)
|
||||||
|
{
|
||||||
|
if (!_workspaceAccessor.TryGetWorkspace(_project.ParentSolution, out var workspace))
|
||||||
|
{
|
||||||
|
// Could not locate workspace for razor project. Project is most likely tearing down.
|
||||||
|
projectSnapshotManagerBase = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var languageService = workspace.Services.GetLanguageServices(RazorLanguage.Name);
|
||||||
|
projectSnapshotManagerBase = (ProjectSnapshotManagerBase)languageService.GetRequiredService<ProjectSnapshotManager>();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetatchCurrentRazorProjectHost()
|
||||||
|
{
|
||||||
|
_razorProjectHost?.Detatch();
|
||||||
|
_razorProjectHost = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
// Copyright (c) .NET Foundation. 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.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
using MonoDevelop.Projects.MSBuild;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
internal class DefaultRazorProjectHost : RazorProjectHostBase
|
||||||
|
{
|
||||||
|
private const string RazorLangVersionProperty = "RazorLangVersion";
|
||||||
|
private const string RazorDefaultConfigurationProperty = "RazorDefaultConfiguration";
|
||||||
|
private const string RazorExtensionItemType = "RazorExtension";
|
||||||
|
private const string RazorConfigurationItemType = "RazorConfiguration";
|
||||||
|
private const string RazorConfigurationItemTypeExtensionsProperty = "Extensions";
|
||||||
|
|
||||||
|
public DefaultRazorProjectHost(
|
||||||
|
DotNetProject project,
|
||||||
|
ForegroundDispatcher foregroundDispatcher,
|
||||||
|
ProjectSnapshotManagerBase projectSnapshotManager)
|
||||||
|
: base(project, foregroundDispatcher, projectSnapshotManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnProjectChangedAsync()
|
||||||
|
{
|
||||||
|
ForegroundDispatcher.AssertBackgroundThread();
|
||||||
|
|
||||||
|
await ExecuteWithLockAsync(async () =>
|
||||||
|
{
|
||||||
|
var projectProperties = DotNetProject.MSBuildProject.EvaluatedProperties;
|
||||||
|
var projectItems = DotNetProject.MSBuildProject.EvaluatedItems;
|
||||||
|
|
||||||
|
if (TryGetConfiguration(projectProperties, projectItems, out var configuration))
|
||||||
|
{
|
||||||
|
var hostProject = new HostProject(DotNetProject.FileName.FullPath, configuration);
|
||||||
|
await UpdateHostProjectUnsafeAsync(hostProject).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ok we can't find a configuration. Let's assume this project isn't using Razor then.
|
||||||
|
await UpdateHostProjectUnsafeAsync(null).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetConfiguration(
|
||||||
|
IMSBuildEvaluatedPropertyCollection projectProperties,
|
||||||
|
IEnumerable<IMSBuildItemEvaluated> projectItems,
|
||||||
|
out RazorConfiguration configuration)
|
||||||
|
{
|
||||||
|
if (!TryGetDefaultConfiguration(projectProperties, out var defaultConfiguration))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetLanguageVersion(projectProperties, out var languageVersion))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetConfigurationItem(defaultConfiguration, projectItems, out var configurationItem))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames))
|
||||||
|
{
|
||||||
|
configuration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var extensions = GetExtensions(configuredExtensionNames, projectItems);
|
||||||
|
configuration = new ProjectSystemRazorConfiguration(languageVersion, configurationItem.Include, extensions);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetDefaultConfiguration(IMSBuildEvaluatedPropertyCollection projectProperties, out string defaultConfiguration)
|
||||||
|
{
|
||||||
|
defaultConfiguration = projectProperties.GetValue(RazorDefaultConfigurationProperty);
|
||||||
|
if (string.IsNullOrEmpty(defaultConfiguration))
|
||||||
|
{
|
||||||
|
defaultConfiguration = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetLanguageVersion(IMSBuildEvaluatedPropertyCollection projectProperties, out RazorLanguageVersion languageVersion)
|
||||||
|
{
|
||||||
|
var languageVersionValue = projectProperties.GetValue(RazorLangVersionProperty);
|
||||||
|
if (string.IsNullOrEmpty(languageVersionValue))
|
||||||
|
{
|
||||||
|
languageVersion = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RazorLanguageVersion.TryParse(languageVersionValue, out languageVersion))
|
||||||
|
{
|
||||||
|
languageVersion = RazorLanguageVersion.Latest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetConfigurationItem(
|
||||||
|
string configuration,
|
||||||
|
IEnumerable<IMSBuildItemEvaluated> projectItems,
|
||||||
|
out IMSBuildItemEvaluated configurationItem)
|
||||||
|
{
|
||||||
|
foreach (var item in projectItems)
|
||||||
|
{
|
||||||
|
if (item.Name == RazorConfigurationItemType && item.Include == configuration)
|
||||||
|
{
|
||||||
|
configurationItem = item;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurationItem = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool TryGetConfiguredExtensionNames(IMSBuildItemEvaluated configurationItem, out string[] configuredExtensionNames)
|
||||||
|
{
|
||||||
|
var extensionNamesValue = configurationItem.Metadata.GetValue(RazorConfigurationItemTypeExtensionsProperty);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(extensionNamesValue))
|
||||||
|
{
|
||||||
|
configuredExtensionNames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
configuredExtensionNames = extensionNamesValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static ProjectSystemRazorExtension[] GetExtensions(
|
||||||
|
string[] configuredExtensionNames,
|
||||||
|
IEnumerable<IMSBuildItemEvaluated> projectItems)
|
||||||
|
{
|
||||||
|
var extensions = new List<ProjectSystemRazorExtension>();
|
||||||
|
|
||||||
|
foreach (var item in projectItems)
|
||||||
|
{
|
||||||
|
if (item.Name != RazorExtensionItemType)
|
||||||
|
{
|
||||||
|
// Not a RazorExtension
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var extensionName = item.Include;
|
||||||
|
if (configuredExtensionNames.Contains(extensionName))
|
||||||
|
{
|
||||||
|
extensions.Add(new ProjectSystemRazorExtension(extensionName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
internal abstract class DotNetProjectHost
|
||||||
|
{
|
||||||
|
public abstract DotNetProject Project { get; }
|
||||||
|
|
||||||
|
public abstract void Subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright (c) .NET Foundation. 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.ComponentModel.Composition;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
[System.Composition.Shared]
|
||||||
|
[Export(typeof(DotNetProjectHostFactory))]
|
||||||
|
internal class DotNetProjectHostFactory
|
||||||
|
{
|
||||||
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
|
private readonly VisualStudioMacWorkspaceAccessor _workspaceAccessor;
|
||||||
|
private readonly TextBufferProjectService _projectService;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public DotNetProjectHostFactory(
|
||||||
|
ForegroundDispatcher foregroundDispatcher,
|
||||||
|
VisualStudioMacWorkspaceAccessor workspaceAccessor,
|
||||||
|
TextBufferProjectService projectService)
|
||||||
|
{
|
||||||
|
if (foregroundDispatcher == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(foregroundDispatcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspaceAccessor == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspaceAccessor));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectService == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectService));
|
||||||
|
}
|
||||||
|
|
||||||
|
_foregroundDispatcher = foregroundDispatcher;
|
||||||
|
_workspaceAccessor = workspaceAccessor;
|
||||||
|
_projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DotNetProjectHost Create(DotNetProject project)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectHost = new DefaultDotNetProjectHost(project, _foregroundDispatcher, _workspaceAccessor, _projectService);
|
||||||
|
return projectHost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
// Copyright (c) .NET Foundation. 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.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Reflection.PortableExecutable;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
using AssemblyReference = MonoDevelop.Projects.AssemblyReference;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
internal class FallbackRazorProjectHost : RazorProjectHostBase
|
||||||
|
{
|
||||||
|
private const string MvcAssemblyFileName = "Microsoft.AspNetCore.Mvc.Razor.dll";
|
||||||
|
|
||||||
|
public FallbackRazorProjectHost(
|
||||||
|
DotNetProject project,
|
||||||
|
ForegroundDispatcher foregroundDispatcher,
|
||||||
|
ProjectSnapshotManagerBase projectSnapshotManager)
|
||||||
|
: base(project, foregroundDispatcher, projectSnapshotManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnProjectChangedAsync()
|
||||||
|
{
|
||||||
|
ForegroundDispatcher.AssertBackgroundThread();
|
||||||
|
|
||||||
|
await ExecuteWithLockAsync(async () =>
|
||||||
|
{
|
||||||
|
var referencedAssemblies = await DotNetProject.GetReferencedAssemblies(ConfigurationSelector.Default);
|
||||||
|
var mvcReference = referencedAssemblies.FirstOrDefault(IsMvcAssembly);
|
||||||
|
|
||||||
|
if (mvcReference == null)
|
||||||
|
{
|
||||||
|
// Ok we can't find an MVC version. Let's assume this project isn't using Razor then.
|
||||||
|
await UpdateHostProjectUnsafeAsync(null).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var version = GetAssemblyVersion(mvcReference.FilePath);
|
||||||
|
if (version == null)
|
||||||
|
{
|
||||||
|
// Ok we can't find an MVC version. Let's assume this project isn't using Razor then.
|
||||||
|
await UpdateHostProjectUnsafeAsync(null).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var configuration = FallbackRazorConfiguration.SelectConfiguration(version);
|
||||||
|
var hostProject = new HostProject(DotNetProject.FileName.FullPath, configuration);
|
||||||
|
await UpdateHostProjectUnsafeAsync(hostProject).ConfigureAwait(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal for testing
|
||||||
|
internal static bool IsMvcAssembly(AssemblyReference reference)
|
||||||
|
{
|
||||||
|
var fileName = reference?.FilePath.FileName;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(fileName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(reference.FilePath.FileName, MvcAssemblyFileName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// Mvc assembly
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Version GetAssemblyVersion(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
|
||||||
|
using (var reader = new PEReader(stream))
|
||||||
|
{
|
||||||
|
var metadataReader = reader.GetMetadataReader();
|
||||||
|
|
||||||
|
var assemblyDefinition = metadataReader.GetAssemblyDefinition();
|
||||||
|
return assemblyDefinition.Version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// We're purposely silencing any kinds of I/O exceptions here, just in case something wacky is going on.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
// Copyright (c) .NET Foundation. 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.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Microsoft.VisualStudio.Threading;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
internal abstract class RazorProjectHostBase
|
||||||
|
{
|
||||||
|
// References changes are always triggered when project changes happen.
|
||||||
|
private const string ProjectChangedHint = "References";
|
||||||
|
|
||||||
|
private bool _batchingProjectChanges;
|
||||||
|
private readonly DotNetProject _dotNetProject;
|
||||||
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
|
private readonly ProjectSnapshotManagerBase _projectSnapshotManager;
|
||||||
|
private readonly AsyncSemaphore _onProjectChangedInnerSemaphore;
|
||||||
|
private readonly AsyncSemaphore _projectChangedSemaphore;
|
||||||
|
private HostProject _currentHostProject;
|
||||||
|
|
||||||
|
public RazorProjectHostBase(
|
||||||
|
DotNetProject project,
|
||||||
|
ForegroundDispatcher foregroundDispatcher,
|
||||||
|
ProjectSnapshotManagerBase projectSnapshotManager)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foregroundDispatcher == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(foregroundDispatcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectSnapshotManager == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectSnapshotManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
_dotNetProject = project;
|
||||||
|
_foregroundDispatcher = foregroundDispatcher;
|
||||||
|
_projectSnapshotManager = projectSnapshotManager;
|
||||||
|
_onProjectChangedInnerSemaphore = new AsyncSemaphore(initialCount: 1);
|
||||||
|
_projectChangedSemaphore = new AsyncSemaphore(initialCount: 1);
|
||||||
|
|
||||||
|
AttachToProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DotNetProject DotNetProject => _dotNetProject;
|
||||||
|
|
||||||
|
public HostProject HostProject => _currentHostProject;
|
||||||
|
|
||||||
|
protected ForegroundDispatcher ForegroundDispatcher => _foregroundDispatcher;
|
||||||
|
|
||||||
|
public void Detatch()
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
DotNetProject.Modified -= DotNetProject_Modified;
|
||||||
|
|
||||||
|
UpdateHostProjectForeground(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Task OnProjectChangedAsync();
|
||||||
|
|
||||||
|
// Protected virtual for testing
|
||||||
|
protected virtual void AttachToProject()
|
||||||
|
{
|
||||||
|
ForegroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
DotNetProject.Modified += DotNetProject_Modified;
|
||||||
|
|
||||||
|
// Trigger the initial update to the project.
|
||||||
|
_batchingProjectChanges = true;
|
||||||
|
Task.Factory.StartNew(ProjectChangedBackgroundAsync, null, CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.BackgroundScheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be called inside the lock.
|
||||||
|
protected async Task UpdateHostProjectUnsafeAsync(HostProject newHostProject)
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertBackgroundThread();
|
||||||
|
|
||||||
|
await Task.Factory.StartNew(UpdateHostProjectForeground, newHostProject, CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.ForegroundScheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task ExecuteWithLockAsync(Func<Task> func)
|
||||||
|
{
|
||||||
|
using (await _projectChangedSemaphore.EnterAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await func().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProjectChangedBackgroundAsync(object state)
|
||||||
|
{
|
||||||
|
ForegroundDispatcher.AssertBackgroundThread();
|
||||||
|
|
||||||
|
_batchingProjectChanges = false;
|
||||||
|
|
||||||
|
// Ensure ordering, typically we'll only have 1 background thread in flight at a time. However,
|
||||||
|
// between this line and the one prior another background thread could have also entered this
|
||||||
|
// method. This is here to protect against us changing the order of project changed events.
|
||||||
|
using (await _onProjectChangedInnerSemaphore.EnterAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
await OnProjectChangedAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DotNetProject_Modified(object sender, SolutionItemModifiedEventArgs args)
|
||||||
|
{
|
||||||
|
if (args == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
ForegroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
if (_batchingProjectChanges)
|
||||||
|
{
|
||||||
|
// Already waiting to recompute host project, no need to do any more work to determine if we're dirty.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectChanged = args.Any(arg => string.Equals(arg.Hint, ProjectChangedHint, StringComparison.Ordinal));
|
||||||
|
if (projectChanged)
|
||||||
|
{
|
||||||
|
// This method can be spammed for tons of project change events but all we really care about is "are we dirty?".
|
||||||
|
// Therefore, we re-dispatch here to allow any remaining project change events to fire and to then only have 1 host
|
||||||
|
// project change trigger; this way we don't spam our own system with re-configure calls.
|
||||||
|
_batchingProjectChanges = true;
|
||||||
|
Task.Factory.StartNew(ProjectChangedBackgroundAsync, null, CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.BackgroundScheduler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateHostProjectForeground(object state)
|
||||||
|
{
|
||||||
|
_foregroundDispatcher.AssertForegroundThread();
|
||||||
|
|
||||||
|
var newHostProject = (HostProject)state;
|
||||||
|
|
||||||
|
if (_currentHostProject == null && newHostProject == null)
|
||||||
|
{
|
||||||
|
// This is a no-op. This project isn't using Razor.
|
||||||
|
}
|
||||||
|
else if (_currentHostProject == null && newHostProject != null)
|
||||||
|
{
|
||||||
|
_projectSnapshotManager.HostProjectAdded(newHostProject);
|
||||||
|
}
|
||||||
|
else if (_currentHostProject != null && newHostProject == null)
|
||||||
|
{
|
||||||
|
_projectSnapshotManager.HostProjectRemoved(HostProject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_projectSnapshotManager.HostProjectChanged(newHostProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentHostProject = newHostProject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,5 +3,6 @@
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Mac.RazorAddin, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
using Workspace = Microsoft.CodeAnalysis.Workspace;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor
|
||||||
|
{
|
||||||
|
internal abstract class VisualStudioMacWorkspaceAccessor : VisualStudioWorkspaceAccessor
|
||||||
|
{
|
||||||
|
public abstract bool TryGetWorkspace(Solution solution, out Workspace workspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,12 +3,16 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.VisualStudio.LanguageServices.Razor;
|
using Microsoft.VisualStudio.LanguageServices.Razor;
|
||||||
using Microsoft.VisualStudio.ProjectSystem;
|
using Microsoft.VisualStudio.ProjectSystem;
|
||||||
|
using Microsoft.VisualStudio.ProjectSystem.Properties;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using ProjectStateItem = System.Collections.Generic.KeyValuePair<string, System.Collections.Immutable.IImmutableDictionary<string, string>>;
|
||||||
|
|
||||||
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
{
|
{
|
||||||
|
|
@ -24,6 +28,571 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
|
|
||||||
private Workspace Workspace { get; }
|
private Workspace Workspace { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetDefaultConfiguration_FailsIfNoRule()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>().ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetDefaultConfiguration(projectState, out var defaultConfiguration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(defaultConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetDefaultConfiguration_FailsIfNoConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(Rules.RazorGeneral.SchemaName, new Dictionary<string, string>())
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetDefaultConfiguration(projectState, out var defaultConfiguration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(defaultConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetDefaultConfiguration_FailsIfEmptyConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorDefaultConfigurationProperty] = string.Empty
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetDefaultConfiguration(projectState, out var defaultConfiguration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(defaultConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetDefaultConfiguration_SucceedsWithValidConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedConfiguration = "Razor-13.37";
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorDefaultConfigurationProperty] = expectedConfiguration
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetDefaultConfiguration(projectState, out var defaultConfiguration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal(expectedConfiguration, defaultConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_FailsIfNoRule()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>().ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectState, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_FailsIfNoLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(Rules.RazorGeneral.SchemaName, new Dictionary<string, string>())
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectState, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_FailsIfEmptyLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorLangVersionProperty] = string.Empty
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectState, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_SucceedsWithValidLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorLangVersionProperty] = "1.0"
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectState, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Same(RazorLanguageVersion.Version_1_0, languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_SucceedsWithUnknownLanguageVersion_DefaultsToLatest()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorLangVersionProperty] = "13.37"
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectState, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Same(RazorLanguageVersion.Latest, languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfigurationItem_FailsNoRazorConfigurationRule()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>().ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfigurationItem("Razor-13.37", projectState, out var configurationItem);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfigurationItem_FailsNoRazorConfigurationItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorConfiguration.SchemaName] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorConfiguration.SchemaName,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>())
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfigurationItem("Razor-13.37", projectState, out var configurationItem);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfigurationItem_FailsNoMatchingRazorConfigurationItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorConfiguration.SchemaName] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorConfiguration.SchemaName,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
["Razor-10.0"] = new Dictionary<string, string>(),
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfigurationItem("Razor-13.37", projectState, out var configurationItem);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfigurationItem_SucceedsForMatchingConfigurationItem()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedConfiguration = "Razor-13.37";
|
||||||
|
var expectedConfigurationValue = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorConfiguration.ExtensionsProperty] = "SomeExtension"
|
||||||
|
};
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorConfiguration.SchemaName] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorConfiguration.SchemaName,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
[expectedConfiguration] = expectedConfigurationValue
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfigurationItem(expectedConfiguration, projectState, out var configurationItem);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal(expectedConfiguration, configurationItem.Key);
|
||||||
|
Assert.True(Enumerable.SequenceEqual(expectedConfigurationValue, configurationItem.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_FailsIfNoExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var extensions = new Dictionary<string, string>().ToImmutableDictionary();
|
||||||
|
var configurationItem = new ProjectStateItem(Rules.RazorConfiguration.SchemaName, extensions);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionnames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuredExtensionnames);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_FailsIfEmptyExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var extensions = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorConfiguration.ExtensionsProperty] = string.Empty
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
var configurationItem = new ProjectStateItem(Rules.RazorConfiguration.SchemaName, extensions);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuredExtensionNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_SucceedsIfSingleExtension()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedExtensionName = "SomeExtensionName";
|
||||||
|
var extensions = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorConfiguration.ExtensionsProperty] = expectedExtensionName
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
var configurationItem = new ProjectStateItem(Rules.RazorConfiguration.SchemaName, extensions);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
var extensionName = Assert.Single(configuredExtensionNames);
|
||||||
|
Assert.Equal(expectedExtensionName, extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_SucceedsIfMultipleExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var extensions = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorConfiguration.ExtensionsProperty] = "SomeExtensionName;SomeOtherExtensionName"
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
var configurationItem = new ProjectStateItem(Rules.RazorConfiguration.SchemaName, extensions);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Collection(
|
||||||
|
configuredExtensionNames,
|
||||||
|
name => Assert.Equal("SomeExtensionName", name),
|
||||||
|
name => Assert.Equal("SomeOtherExtensionName", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetExtensions_NoExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>().ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetExtensions(new[] { "Extension1", "Extension2" }, projectState, out var extensions);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetExtensions_SucceedsWithUnConfiguredExtensionTypes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorExtension.PrimaryDataSourceItemType] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorExtension.PrimaryDataSourceItemType,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
["UnconfiguredExtensionName"] = new Dictionary<string, string>()
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetExtensions(new[] { "Extension1", "Extension2" }, projectState, out var extensions);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Empty(extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetExtensions_SucceedsWithSomeConfiguredExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedExtension1Name = "Extension1";
|
||||||
|
var expectedExtension2Name = "Extension2";
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorExtension.PrimaryDataSourceItemType] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorExtension.PrimaryDataSourceItemType,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
["UnconfiguredExtensionName"] = new Dictionary<string, string>(),
|
||||||
|
[expectedExtension1Name] = new Dictionary<string, string>(),
|
||||||
|
[expectedExtension2Name] = new Dictionary<string, string>(),
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetExtensions(new[] { expectedExtension1Name, expectedExtension2Name }, projectState, out var extensions);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Collection(
|
||||||
|
extensions,
|
||||||
|
extension => Assert.Equal(expectedExtension2Name, extension.ExtensionName),
|
||||||
|
extension => Assert.Equal(expectedExtension1Name, extension.ExtensionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoDefaultConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>().ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectState, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorDefaultConfigurationProperty] = "13.37"
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectState, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoConfigurationItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorDefaultConfigurationProperty] = "13.37",
|
||||||
|
[Rules.RazorGeneral.RazorLangVersionProperty] = "1.0",
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectState, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoConfiguredExtensionNames()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorDefaultConfigurationProperty] = "13.37",
|
||||||
|
[Rules.RazorGeneral.RazorLangVersionProperty] = "1.0",
|
||||||
|
}),
|
||||||
|
[Rules.RazorConfiguration.SchemaName] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorConfiguration.SchemaName,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
["Razor-13.37"] = new Dictionary<string, string>()
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectState, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorDefaultConfigurationProperty] = "13.37",
|
||||||
|
[Rules.RazorGeneral.RazorLangVersionProperty] = "1.0",
|
||||||
|
}),
|
||||||
|
[Rules.RazorConfiguration.SchemaName] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorConfiguration.SchemaName,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
["SomeExtension"] = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
["Extensions"] = "Razor-13.37"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectState, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is more of an integration test but is here to test the overall flow/functionality
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_SucceedsWithAllPreRequisites()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedLanguageVersion = RazorLanguageVersion.Version_1_0;
|
||||||
|
var expectedConfigurationName = "Razor-Test";
|
||||||
|
var expectedExtension1Name = "Extension1";
|
||||||
|
var expectedExtension2Name = "Extension2";
|
||||||
|
var projectState = new Dictionary<string, IProjectRuleSnapshot>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.SchemaName] = TestProjectRuleSnapshot.CreateProperties(
|
||||||
|
Rules.RazorGeneral.SchemaName,
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[Rules.RazorGeneral.RazorDefaultConfigurationProperty] = expectedConfigurationName,
|
||||||
|
[Rules.RazorGeneral.RazorLangVersionProperty] = "1.0",
|
||||||
|
}),
|
||||||
|
[Rules.RazorConfiguration.SchemaName] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorConfiguration.SchemaName,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
["UnconfiguredRazorConfiguration"] = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
["Extensions"] = "Razor-9.0"
|
||||||
|
},
|
||||||
|
[expectedConfigurationName] = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
["Extensions"] = expectedExtension1Name + ";" + expectedExtension2Name
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
[Rules.RazorExtension.PrimaryDataSourceItemType] = TestProjectRuleSnapshot.CreateItems(
|
||||||
|
Rules.RazorExtension.PrimaryDataSourceItemType,
|
||||||
|
new Dictionary<string, Dictionary<string, string>>()
|
||||||
|
{
|
||||||
|
[expectedExtension1Name] = new Dictionary<string, string>(),
|
||||||
|
[expectedExtension2Name] = new Dictionary<string, string>(),
|
||||||
|
})
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectState, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal(expectedLanguageVersion, configuration.LanguageVersion);
|
||||||
|
Assert.Equal(expectedConfigurationName, configuration.ConfigurationName);
|
||||||
|
Assert.Collection(
|
||||||
|
configuration.Extensions,
|
||||||
|
extension => Assert.Equal(expectedExtension2Name, extension.ExtensionName),
|
||||||
|
extension => Assert.Equal(expectedExtension1Name, extension.ExtensionName));
|
||||||
|
}
|
||||||
|
|
||||||
[ForegroundFact]
|
[ForegroundFact]
|
||||||
public async Task DefaultRazorProjectHost_ForegroundThread_CreateAndDispose_Succeeds()
|
public async Task DefaultRazorProjectHost_ForegroundThread_CreateAndDispose_Succeeds()
|
||||||
{
|
{
|
||||||
|
|
@ -232,8 +801,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
Assert.Equal("MVC-2.0", snapshot.Configuration.ConfigurationName);
|
Assert.Equal("MVC-2.0", snapshot.Configuration.ConfigurationName);
|
||||||
Assert.Collection(
|
Assert.Collection(
|
||||||
snapshot.Configuration.Extensions,
|
snapshot.Configuration.Extensions,
|
||||||
e => Assert.Equal("MVC-2.0", e.ExtensionName),
|
e => Assert.Equal("Another-Thing", e.ExtensionName),
|
||||||
e => Assert.Equal("Another-Thing", e.ExtensionName));
|
e => Assert.Equal("MVC-2.0", e.ExtensionName));
|
||||||
|
|
||||||
await Task.Run(async () => await host.DisposeAsync());
|
await Task.Run(async () => await host.DisposeAsync());
|
||||||
Assert.Empty(ProjectManager.Projects);
|
Assert.Empty(ProjectManager.Projects);
|
||||||
|
|
@ -443,7 +1012,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
|
|
||||||
private class TestProjectSnapshotManager : DefaultProjectSnapshotManager
|
private class TestProjectSnapshotManager : DefaultProjectSnapshotManager
|
||||||
{
|
{
|
||||||
public TestProjectSnapshotManager(ForegroundDispatcher dispatcher, Workspace workspace)
|
public TestProjectSnapshotManager(ForegroundDispatcher dispatcher, Workspace workspace)
|
||||||
: base(dispatcher, Mock.Of<ErrorReporter>(), Mock.Of<ProjectSnapshotWorker>(), Array.Empty<ProjectSnapshotChangeTrigger>(), workspace)
|
: base(dispatcher, Mock.Of<ErrorReporter>(), Mock.Of<ProjectSnapshotWorker>(), Array.Empty<ProjectSnapshotChangeTrigger>(), workspace)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
public class DefaultDotNetProjectHostTest : ForegroundDispatcherTestBase
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void UpdateRazorHostProject_UnsupportedProjectNoops()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectService = new Mock<TextBufferProjectService>();
|
||||||
|
projectService.Setup(p => p.IsSupportedProject(It.IsAny<object>()))
|
||||||
|
.Returns(false);
|
||||||
|
var dotNetProjectHost = new DefaultDotNetProjectHost(
|
||||||
|
Dispatcher,
|
||||||
|
Mock.Of<VisualStudioMacWorkspaceAccessor>(),
|
||||||
|
projectService.Object);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
dotNetProjectHost.UpdateRazorHostProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
// Purposefully do not have any more tests here because that would involve mocking MonoDevelop
|
||||||
|
// types. The default constructors for the Solution / DotNetProject MonoDevelop types change
|
||||||
|
// static classes (they assume they're being created in an IDE).
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,470 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using MonoDevelop.Projects.MSBuild;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
public class DefaultRazorProjectHostTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void TryGetDefaultConfiguration_FailsIfNoConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetDefaultConfiguration(projectProperties, out var defaultConfiguration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(defaultConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetDefaultConfiguration_FailsIfEmptyConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorDefaultConfiguration", string.Empty);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetDefaultConfiguration(projectProperties, out var defaultConfiguration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(defaultConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetDefaultConfiguration_SucceedsWithValidConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedConfiguration = "Razor-13.37";
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorDefaultConfiguration", expectedConfiguration);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetDefaultConfiguration(projectProperties, out var defaultConfiguration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal(expectedConfiguration, defaultConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_FailsIfNoLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectProperties, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_FailsIfEmptyLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorLangVersion", string.Empty);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectProperties, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_SucceedsWithValidLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorLangVersion", "1.0");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectProperties, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Same(RazorLanguageVersion.Version_1_0, languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetLanguageVersion_SucceedsWithUnknownLanguageVersion_DefaultsToLatest()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorLangVersion", "13.37");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetLanguageVersion(projectProperties, out var languageVersion);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Same(RazorLanguageVersion.Latest, languageVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfigurationItem_FailsNoRazorConfigurationItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectItems = Enumerable.Empty<IMSBuildItemEvaluated>();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfigurationItem("Razor-13.37", projectItems, out var configurationItem);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configurationItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfigurationItem_FailsNoMatchingRazorConfigurationItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[]
|
||||||
|
{
|
||||||
|
new TestMSBuildItem("RazorConfiguration")
|
||||||
|
{
|
||||||
|
Include = "Razor-10.0",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfigurationItem("Razor-13.37", projectItems, out var configurationItem);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configurationItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfigurationItem_SucceedsForMatchingConfigurationItem()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedConfiguration = "Razor-13.37";
|
||||||
|
var expectedConfigurationItem = new TestMSBuildItem("RazorConfiguration")
|
||||||
|
{
|
||||||
|
Include = expectedConfiguration,
|
||||||
|
};
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[]
|
||||||
|
{
|
||||||
|
new TestMSBuildItem("RazorConfiguration")
|
||||||
|
{
|
||||||
|
Include = "Razor-10.0-DoesNotMatch",
|
||||||
|
},
|
||||||
|
expectedConfigurationItem
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfigurationItem(expectedConfiguration, projectItems, out var configurationItem);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Same(expectedConfigurationItem, configurationItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_FailsIfNoExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var configurationItem = new TestMSBuildItem("RazorConfiguration");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionnames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuredExtensionnames);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_FailsIfEmptyExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var configurationItem = new TestMSBuildItem("RazorConfiguration");
|
||||||
|
configurationItem.TestMetadata.SetValue("Extensions", string.Empty);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuredExtensionNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_SucceedsIfSingleExtension()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedExtensionName = "SomeExtensionName";
|
||||||
|
var configurationItem = new TestMSBuildItem("RazorConfiguration");
|
||||||
|
configurationItem.TestMetadata.SetValue("Extensions", expectedExtensionName);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
var extensionName = Assert.Single(configuredExtensionNames);
|
||||||
|
Assert.Equal(expectedExtensionName, extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguredExtensionNames_SucceedsIfMultipleExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var configurationItem = new TestMSBuildItem("RazorConfiguration");
|
||||||
|
configurationItem.TestMetadata.SetValue("Extensions", "SomeExtensionName;SomeOtherExtensionName");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguredExtensionNames(configurationItem, out var configuredExtensionNames);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Collection(
|
||||||
|
configuredExtensionNames,
|
||||||
|
name => Assert.Equal("SomeExtensionName", name),
|
||||||
|
name => Assert.Equal("SomeOtherExtensionName", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetExtensions_NoExtensionTypes_ReturnsEmptyArray()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[]
|
||||||
|
{
|
||||||
|
new TestMSBuildItem("NotAnExtension")
|
||||||
|
{
|
||||||
|
Include = "Extension1",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var extensions = DefaultRazorProjectHost.GetExtensions(new[] { "Extension1", "Extension2" }, projectItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetExtensions_UnConfiguredExtensionTypes_ReturnsEmptyArray()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[]
|
||||||
|
{
|
||||||
|
new TestMSBuildItem("RazorExtension")
|
||||||
|
{
|
||||||
|
Include = "UnconfiguredExtensionName",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var extensions = DefaultRazorProjectHost.GetExtensions(new[] { "Extension1", "Extension2" }, projectItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetExtensions_SomeConfiguredExtensions_ReturnsConfiguredExtensions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedExtension1Name = "Extension1";
|
||||||
|
var expectedExtension2Name = "Extension2";
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[]
|
||||||
|
{
|
||||||
|
new TestMSBuildItem("RazorExtension")
|
||||||
|
{
|
||||||
|
Include = "UnconfiguredExtensionName",
|
||||||
|
},
|
||||||
|
new TestMSBuildItem("RazorExtension")
|
||||||
|
{
|
||||||
|
Include = expectedExtension1Name,
|
||||||
|
},
|
||||||
|
new TestMSBuildItem("RazorExtension")
|
||||||
|
{
|
||||||
|
Include = expectedExtension2Name,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var extensions = DefaultRazorProjectHost.GetExtensions(new[] { expectedExtension1Name, expectedExtension2Name }, projectItems);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
extensions,
|
||||||
|
extension => Assert.Equal(expectedExtension1Name, extension.ExtensionName),
|
||||||
|
extension => Assert.Equal(expectedExtension2Name, extension.ExtensionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoDefaultConfiguration()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[0];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectProperties, projectItems, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoLanguageVersion()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorDefaultConfiguration", "Razor-13.37");
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[0];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectProperties, projectItems, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoConfigurationItems()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorDefaultConfiguration", "Razor-13.37");
|
||||||
|
projectProperties.SetValue("RazorLangVersion", "1.0");
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[0];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectProperties, projectItems, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_FailsIfNoConfiguredExtensionNames()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorDefaultConfiguration", "Razor-13.37");
|
||||||
|
projectProperties.SetValue("RazorLangVersion", "1.0");
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[]
|
||||||
|
{
|
||||||
|
new TestMSBuildItem("RazorConfiguration")
|
||||||
|
{
|
||||||
|
Include = "Razor-13.37",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectProperties, projectItems, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is more of an integration test but is here to test the overall flow/functionality
|
||||||
|
[Fact]
|
||||||
|
public void TryGetConfiguration_SucceedsWithAllPreRequisites()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedLanguageVersion = RazorLanguageVersion.Version_1_0;
|
||||||
|
var expectedConfigurationName = "Razor-Test";
|
||||||
|
var expectedExtension1Name = "Extension1";
|
||||||
|
var expectedExtension2Name = "Extension2";
|
||||||
|
var expectedRazorConfigurationItem = new TestMSBuildItem("RazorConfiguration")
|
||||||
|
{
|
||||||
|
Include = expectedConfigurationName,
|
||||||
|
};
|
||||||
|
expectedRazorConfigurationItem.TestMetadata.SetValue("Extensions", "Extension1;Extension2");
|
||||||
|
var projectItems = new IMSBuildItemEvaluated[]
|
||||||
|
{
|
||||||
|
new TestMSBuildItem("RazorConfiguration")
|
||||||
|
{
|
||||||
|
Include = "UnconfiguredRazorConfiguration",
|
||||||
|
},
|
||||||
|
new TestMSBuildItem("RazorExtension")
|
||||||
|
{
|
||||||
|
Include = "UnconfiguredExtensionName",
|
||||||
|
},
|
||||||
|
new TestMSBuildItem("RazorExtension")
|
||||||
|
{
|
||||||
|
Include = expectedExtension1Name,
|
||||||
|
},
|
||||||
|
new TestMSBuildItem("RazorExtension")
|
||||||
|
{
|
||||||
|
Include = expectedExtension2Name,
|
||||||
|
},
|
||||||
|
expectedRazorConfigurationItem,
|
||||||
|
};
|
||||||
|
var projectProperties = new MSBuildPropertyGroup();
|
||||||
|
projectProperties.SetValue("RazorDefaultConfiguration", expectedConfigurationName);
|
||||||
|
projectProperties.SetValue("RazorLangVersion", "1.0");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = DefaultRazorProjectHost.TryGetConfiguration(projectProperties, projectItems, out var configuration);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal(expectedLanguageVersion, configuration.LanguageVersion);
|
||||||
|
Assert.Equal(expectedConfigurationName, configuration.ConfigurationName);
|
||||||
|
Assert.Collection(
|
||||||
|
configuration.Extensions,
|
||||||
|
extension => Assert.Equal(expectedExtension1Name, extension.ExtensionName),
|
||||||
|
extension => Assert.Equal(expectedExtension2Name, extension.ExtensionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestMSBuildItem : IMSBuildItemEvaluated
|
||||||
|
{
|
||||||
|
private readonly MSBuildPropertyGroup _metadata;
|
||||||
|
private readonly string _name;
|
||||||
|
private string _include;
|
||||||
|
|
||||||
|
public TestMSBuildItem(string name)
|
||||||
|
{
|
||||||
|
_name = name;
|
||||||
|
_metadata = new MSBuildPropertyGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => _name;
|
||||||
|
|
||||||
|
public string Include
|
||||||
|
{
|
||||||
|
get => _include;
|
||||||
|
set => _include = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MSBuildPropertyGroup TestMetadata => _metadata;
|
||||||
|
|
||||||
|
public IMSBuildPropertyGroupEvaluated Metadata => _metadata;
|
||||||
|
|
||||||
|
public string Condition => throw new System.NotImplementedException();
|
||||||
|
|
||||||
|
public bool IsImported => throw new System.NotImplementedException();
|
||||||
|
|
||||||
|
|
||||||
|
public string UnevaluatedInclude => throw new System.NotImplementedException();
|
||||||
|
|
||||||
|
public MSBuildItem SourceItem => throw new System.NotImplementedException();
|
||||||
|
|
||||||
|
public IEnumerable<MSBuildItem> SourceItems => throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,13 +8,13 @@ using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor
|
||||||
{
|
{
|
||||||
public class DefaultVisualStudioWorkspaceAccessorTest
|
public class DefaultVisualStudioMacWorkspaceAccessorTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TryGetWorkspace_NoHostProject_ReturnsFalse()
|
public void TryGetWorkspace_NoHostProject_ReturnsFalse()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<TextBufferProjectService>());
|
var workspaceAccessor = new DefaultVisualStudioMacWorkspaceAccessor(Mock.Of<TextBufferProjectService>());
|
||||||
var textBuffer = Mock.Of<ITextBuffer>();
|
var textBuffer = Mock.Of<ITextBuffer>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using MonoDevelop.Core;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
public class FallbackRazorProjectHostTest
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(null)]
|
||||||
|
[InlineData("")]
|
||||||
|
public void IsMvcAssembly_FailsIfNullOrEmptyFilePath(string filePath)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var assemblyFilePath = new FilePath(filePath);
|
||||||
|
var assemblyReference = new AssemblyReference(assemblyFilePath);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = FallbackRazorProjectHost.IsMvcAssembly(assemblyReference);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsMvcAssembly_FailsIfNotMvc()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var assemblyFilePath = new FilePath("C:/Path/To/Assembly.dll");
|
||||||
|
var assemblyReference = new AssemblyReference(assemblyFilePath);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = FallbackRazorProjectHost.IsMvcAssembly(assemblyReference);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsMvcAssembly_SucceedsIfMvc()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var assemblyFilePath = new FilePath("C:/Path/To/Microsoft.AspNetCore.Mvc.Razor.dll");
|
||||||
|
var assemblyReference = new AssemblyReference(assemblyFilePath);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = FallbackRazorProjectHost.IsMvcAssembly(assemblyReference);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
// Purposefully do not have any more tests here because that would involve mocking MonoDevelop
|
||||||
|
// types. The default constructors for the Solution / DotNetProject MonoDevelop types change
|
||||||
|
// static classes (they assume they're being created in an IDE).
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
<TargetFramework>net461</TargetFramework>
|
<TargetFramework>net461</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Microsoft.VisualStudio.Mac.LanguageServices.Razor\Microsoft.VisualStudio.Mac.LanguageServices.Razor.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.VisualStudio.Mac.LanguageServices.Razor\Microsoft.VisualStudio.Mac.LanguageServices.Razor.csproj" />
|
||||||
<ProjectReference Include="..\Microsoft.VisualStudio.Editor.Razor.Test.Common\Microsoft.VisualStudio.Editor.Razor.Test.Common.csproj" />
|
<ProjectReference Include="..\Microsoft.VisualStudio.Editor.Razor.Test.Common\Microsoft.VisualStudio.Editor.Razor.Test.Common.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"methodDisplay": "method",
|
||||||
|
"shadowCopy": false
|
||||||
|
}
|
||||||
|
|
@ -42,15 +42,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!--
|
<ProjectReference Include="..\..\src\Microsoft.VisualStudio.Mac.LanguageServices.Razor\Microsoft.VisualStudio.Mac.LanguageServices.Razor.csproj" />
|
||||||
The extension project can not have a direct reference to its language service pieces. They are included via the manifest above.
|
|
||||||
This piece ensures that transitive builds/restores occurr for this project.
|
|
||||||
-->
|
|
||||||
<ProjectReference Include="..\..\src\Microsoft.VisualStudio.Mac.LanguageServices.Razor\Microsoft.VisualStudio.Mac.LanguageServices.Razor.csproj">
|
|
||||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
|
||||||
<PrivateAssets>true</PrivateAssets>
|
|
||||||
<OutputItemType>Content</OutputItemType>
|
|
||||||
<Targets>Build</Targets>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,10 @@
|
||||||
<Assembly file="Microsoft.VisualStudio.Editor.Razor.dll" />
|
<Assembly file="Microsoft.VisualStudio.Editor.Razor.dll" />
|
||||||
<Assembly file="Microsoft.CodeAnalysis.Razor.Workspaces.dll" />
|
<Assembly file="Microsoft.CodeAnalysis.Razor.Workspaces.dll" />
|
||||||
<Assembly file="Microsoft.VisualStudio.Mac.LanguageServices.Razor.dll" />
|
<Assembly file="Microsoft.VisualStudio.Mac.LanguageServices.Razor.dll" />
|
||||||
</Extension>
|
</Extension>
|
||||||
|
|
||||||
|
<!-- Project Extensions -->
|
||||||
|
<Extension path = "/MonoDevelop/ProjectModel/ProjectModelExtensions">
|
||||||
|
<Class class="Microsoft.VisualStudio.Mac.RazorAddin.RazorProjectExtension" insertafter="FinalStep" />
|
||||||
|
</Extension>
|
||||||
</ExtensionModel>
|
</ExtensionModel>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem;
|
||||||
|
using MonoDevelop.Ide.Composition;
|
||||||
|
using MonoDevelop.Ide.TypeSystem;
|
||||||
|
using MonoDevelop.Projects;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Mac.RazorAddin
|
||||||
|
{
|
||||||
|
internal class RazorProjectExtension : ProjectExtension
|
||||||
|
{
|
||||||
|
private readonly object _lock = new object();
|
||||||
|
private readonly ForegroundDispatcher _foregroundDispatcher;
|
||||||
|
|
||||||
|
public RazorProjectExtension()
|
||||||
|
{
|
||||||
|
_foregroundDispatcher = CompositionManager.GetExportedValue<ForegroundDispatcher>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnBoundToSolution()
|
||||||
|
{
|
||||||
|
if (!(Project is DotNetProject dotNetProject))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DotNetProjectHost projectHost;
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (Project.ExtendedProperties.Contains(typeof(DotNetProjectHost)))
|
||||||
|
{
|
||||||
|
// Already have a project host.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectHostFactory = CompositionManager.GetExportedValue<DotNetProjectHostFactory>();
|
||||||
|
projectHost = projectHostFactory.Create(dotNetProject);
|
||||||
|
Project.ExtendedProperties[typeof(DotNetProjectHost)] = projectHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once a workspace is created for the solution we'll setup our project host for the current project. The Razor world
|
||||||
|
// shares a lifetime with the workspace (as Roslyn services) so we need to ensure it exists prior to wiring the host
|
||||||
|
// world to the Roslyn world.
|
||||||
|
TypeSystemService.GetWorkspaceAsync(Project.ParentSolution).ContinueWith(task =>
|
||||||
|
{
|
||||||
|
if (task.IsFaulted || task.IsCanceled)
|
||||||
|
{
|
||||||
|
// We only want to act if we could properly retrieve the workspace.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
projectHost.Subscribe();
|
||||||
|
},
|
||||||
|
_foregroundDispatcher.ForegroundScheduler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue