Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<Compile Include="Mocks\IDebugLaunchProviderMetadataViewFactory.cs" />
<Compile Include="Mocks\IDteServicesFactory.cs" />
<Compile Include="Mocks\ExportFactoryFactory.cs" />
<Compile Include="Mocks\IVsHiearchyItemFactory.cs" />
<Compile Include="Mocks\IProjectFileEditorPresenterFactory.cs" />
<Compile Include="Mocks\IFrameOpenCloseListenerFactory.cs" />
<Compile Include="Mocks\IProjectXmlAccessorFactory.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.VisualStudio.GraphModel;
using Microsoft.VisualStudio.GraphModel.Schemas;
using Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Moq;

Expand All @@ -20,7 +21,8 @@ public static IGraphContext Create()

public static GraphNode CreateNode(string projectPath,
string nodeIdString,
IDependencyNode node = null)
IDependencyNode node = null,
IVsHierarchyItem hierarchyItem = null)
{
var graph = new Graph();
var id = GraphNodeId.GetNested(
Expand All @@ -33,6 +35,10 @@ public static GraphNode CreateNode(string projectPath,
{
graphNode.SetValue(DependenciesGraphSchema.DependencyNodeProperty, node);
}
if (hierarchyItem != null)
{
graphNode.SetValue(HierarchyGraphNodeProperties.HierarchyItem, hierarchyItem);
}

return graphNode;
}
Expand Down Expand Up @@ -120,10 +126,10 @@ public static IGraphContext ImplementSearchAsync(string searchString,
var mockSearchQuery = new Mock<IVsSearchQuery>();
mockSearchQuery.Setup(q => q.SearchString).Returns(searchString);

var mockSearchParameters = new Mock<Shell.ISolutionSearchParameters>();
var mockSearchParameters = new Mock<ISolutionSearchParameters>();
mockSearchParameters.Setup(s => s.SearchQuery).Returns(mockSearchQuery.Object);

mock.Setup(g => g.GetValue<Shell.ISolutionSearchParameters>(It.IsAny<string>())).Returns(mockSearchParameters.Object);
mock.Setup(g => g.GetValue<ISolutionSearchParameters>(It.IsAny<string>())).Returns(mockSearchParameters.Object);
mock.Setup(x => x.OnCompleted());
mock.Setup(x => x.Graph).Returns(new Graph());

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.VisualStudio.Shell;
using Moq;

namespace Microsoft.VisualStudio.ProjectSystem.VS
{
internal static class IVsHierarchyItemFactory
{
public static IVsHierarchyItem Create()
{
return Mock.Of<IVsHierarchyItem>();
}

public static IVsHierarchyItem ImplementProperties(string text = null,
string parentCanonicalName = null,
MockBehavior? mockBehavior = null)
{
var behavior = mockBehavior ?? MockBehavior.Default;
var mock = new Mock<IVsHierarchyItem>(behavior);

if (text != null)
{
mock.Setup(x => x.Text).Returns(text);
}

if (parentCanonicalName != null)
{
var parentMock = new Mock<IVsHierarchyItem>(behavior);
parentMock.Setup(x => x.CanonicalName).Returns(parentCanonicalName);
mock.Setup(x => x.Parent).Returns(parentMock.Object);
}

return mock.Object;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@ public async Task DependenciesGraphProvider_CheckChildrenAsync()
{
var projectPath = @"c:\myproject\project.csproj";
var nodeIdString = @"file:///[MyProvider;MyNodeItemSpec]";
var inputNode = IGraphContextFactory.CreateNode(projectPath, nodeIdString);

var mockVsHierarchyItem = IVsHierarchyItemFactory.ImplementProperties(text: "MyNodeItemSpec");
var inputNode = IGraphContextFactory.CreateNode(projectPath,
nodeIdString,
hierarchyItem: mockVsHierarchyItem);
var rootNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyRootNode""
}
}");
var existingNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
Expand All @@ -38,10 +47,68 @@ public async Task DependenciesGraphProvider_CheckChildrenAsync()
""ItemSpec"": ""MyChildNodeItemSpec""
}
}");
rootNode.AddChild(existingNode);
existingNode.Children.Add(existingChildNode);

var mockProvider = new IProjectDependenciesSubTreeProviderMock();
mockProvider.RootNode = rootNode;
mockProvider.AddTestDependencyNodes(new[] { existingNode });

var mockProjectContextProvider = IDependenciesGraphProjectContextProviderFactory.Implement(projectPath, mockProvider);
var mockGraphContext = IGraphContextFactory.ImplementContainsChildren(inputNode);

var provider = new DependenciesGraphProvider(mockProjectContextProvider,
Mock.Of<SVsServiceProvider>(),
new IProjectThreadingServiceMock().JoinableTaskContext);

// Act
await provider.BeginGetGraphDataAsync(mockGraphContext);

// Assert
Assert.True(inputNode.GetValue<bool>(DgmlNodeProperties.ContainsChildren));
Assert.NotNull(inputNode.GetValue<IDependencyNode>(DependenciesGraphSchema.DependencyNodeProperty));
Assert.Equal(existingNode, inputNode.GetValue<IDependencyNode>(DependenciesGraphSchema.DependencyNodeProperty));
Assert.True(inputNode.GetValue(DependenciesGraphSchema.ProviderProperty) is IProjectDependenciesSubTreeProviderMock);
}

[Fact]
public async Task DependenciesGraphProvider_CheckChildrenAsync_TopLevelNodeWithoutId_ShouldGetProviderFromParent()
{
var projectPath = @"c:\myproject\project.csproj";
var parentNodeIdString = @"file:///[MyProvider;;;]";
var nodeFilePath = @"c:/myproject/MyNodeItemSpec";
var mockVsHierarchyItem = IVsHierarchyItemFactory.ImplementProperties(
text: "MyNodeItemSpec",
parentCanonicalName: parentNodeIdString);
var inputNode = IGraphContextFactory.CreateNode(projectPath,
nodeFilePath,
hierarchyItem: mockVsHierarchyItem);
var rootNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyRootNode""
}
}");
var existingNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyNodeItemSpec""
}
}");
var existingChildNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyChildNodeItemSpec""
}
}");
rootNode.AddChild(existingNode);
existingNode.Children.Add(existingChildNode);

var mockProvider = new IProjectDependenciesSubTreeProviderMock();
mockProvider.RootNode = rootNode;
mockProvider.AddTestDependencyNodes(new[] { existingNode });

var mockProjectContextProvider = IDependenciesGraphProjectContextProviderFactory.Implement(projectPath, mockProvider);
Expand Down Expand Up @@ -109,19 +176,31 @@ public async Task DependenciesGraphProvider_CheckChildrenAsync_HasChildrenFalse(
{
var projectPath = @"c:\myproject\project.csproj";
var nodeIdString = @"file:///[MyProvider;MyNodeItemSpec]";
var inputNode = IGraphContextFactory.CreateNode(projectPath, nodeIdString);

var nodeJson = @"
var mockVsHierarchyItem = IVsHierarchyItemFactory.ImplementProperties(text: "MyNodeItemSpec");
var inputNode = IGraphContextFactory.CreateNode(projectPath,
nodeIdString,
hierarchyItem: mockVsHierarchyItem);
var rootNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyRootNode""
}
}");
var existingNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyNodeItemSpec""
}
}";
}");
rootNode.AddChild(existingNode);

var existingNode = IDependencyNodeFactory.FromJson(nodeJson);
var mockProvider = new IProjectDependenciesSubTreeProviderMock();
mockProvider.RootNode = rootNode;
mockProvider.AddTestDependencyNodes(new[] { existingNode });

var mockProjectContextProvider = IDependenciesGraphProjectContextProviderFactory.Implement(projectPath, mockProvider);

var mockGraphContext = IGraphContextFactory.Implement(CancellationToken.None,
Expand Down Expand Up @@ -247,30 +326,38 @@ public async Task DependenciesGraphProvider_GetChildrenAsync_NoNodeAttachedToInp
{
var projectPath = @"c:\myproject\project.csproj";
var nodeIdString = @"file:///[MyProvider;MyNodeItemSpec]";

var nodeJson = @"
var rootNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyRootNode""
}
}");
var existingNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyNodeItemSpec""
}
}";
var childNodeJson = @"
}");
var existingChildNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyChildNodeItemSpec""
}
}";

var existingNode = IDependencyNodeFactory.FromJson(nodeJson);
var existingChildNode = IDependencyNodeFactory.FromJson(childNodeJson);
}");
rootNode.AddChild(existingNode);
existingNode.Children.Add(existingChildNode);

var inputNode = IGraphContextFactory.CreateNode(projectPath, nodeIdString, null);
var mockVsHierarchyItem = IVsHierarchyItemFactory.ImplementProperties(text: "MyNodeItemSpec");
var inputNode = IGraphContextFactory.CreateNode(projectPath,
nodeIdString,
hierarchyItem:mockVsHierarchyItem);
var outputNodes = new HashSet<GraphNode>();

var mockProvider = new IProjectDependenciesSubTreeProviderMock();
mockProvider.RootNode = rootNode;
mockProvider.AddTestDependencyNodes(new[] { existingNode });

var mockProjectContextProvider = IDependenciesGraphProjectContextProviderFactory.Implement(projectPath, mockProvider);
Expand Down Expand Up @@ -552,6 +639,134 @@ public async Task DependenciesGraphProvider_SearchAsync()
Assert.False(outputArray[4].HasCategory(CodeNodeCategories.ProjectItem));
}

[Fact]
public async Task DependenciesGraphProvider_SearchAsync_TopLevel_GenericNode_WithCustomItemSpec()
{
// Arrange
var searchString = "1.0";
var projectPath = @"c:\myproject\project.csproj";
var rootNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyRootNode""
}
}");

var topNode1 = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyTopNodeItemSpec""
}
}", DependencyNode.GenericDependencyFlags.Union(DependencyNode.CustomItemSpec));
((DependencyNode)topNode1).Name = "TopNodeName";
var childNode1 = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyChildNodeItemSpec1.0""
}
}");
topNode1.Children.Add(childNode1);
rootNode.AddChild(topNode1);

var mockProvider = new IProjectDependenciesSubTreeProviderMock();
mockProvider.RootNode = rootNode;
mockProvider.AddTestDependencyNodes(new[] { topNode1 });
mockProvider.AddSearchResults(new[] { topNode1 });

var mockProjectContextProvider =
IDependenciesGraphProjectContextProviderFactory.Implement(
projectPath, subTreeProviders: new[] { mockProvider });

var outputNodes = new HashSet<GraphNode>();
var mockGraphContext = IGraphContextFactory.ImplementSearchAsync(searchString,
outputNodes: outputNodes);

var provider = new TestableDependenciesGraphProvider(mockProjectContextProvider,
Mock.Of<SVsServiceProvider>(),
new IProjectThreadingServiceMock().JoinableTaskContext);

// Act
await provider.BeginGetGraphDataAsync(mockGraphContext);

// Assert
Assert.Equal(2, outputNodes.Count);

var outputArray = outputNodes.ToArray();
// check if top level nodes got CodeNodeCategories.ProjectItem to make sure
// graph matched them back with IVsHierarchy nodes
Assert.True(outputArray[0].HasCategory(CodeNodeCategories.ProjectItem));
Assert.Equal(1, outputArray[0].OutgoingLinkCount);
Assert.Equal(@"c:/myproject/topnodename", outputArray[0].Id.GetNestedValueByName<Uri>(CodeGraphNodeIdName.File).AbsolutePath);
Assert.False(outputArray[1].HasCategory(CodeNodeCategories.ProjectItem));
}

[Fact]
public async Task DependenciesGraphProvider_SearchAsync_TopLevel_GenericNode_WithNormalItemSpec()
{
// Arrange
var searchString = "1.0";
var projectPath = @"c:\myproject\project.csproj";
var rootNode = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyRootNode""
}
}");

var topNode1 = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyTopNodeItemSpec""
}
}", DependencyNode.GenericDependencyFlags);
((DependencyNode)topNode1).Name = "TopNodeName";
var childNode1 = IDependencyNodeFactory.FromJson(@"
{
""Id"": {
""ProviderType"": ""MyProvider"",
""ItemSpec"": ""MyChildNodeItemSpec1.0""
}
}");
topNode1.Children.Add(childNode1);
rootNode.AddChild(topNode1);

var mockProvider = new IProjectDependenciesSubTreeProviderMock();
mockProvider.RootNode = rootNode;
mockProvider.AddTestDependencyNodes(new[] { topNode1 });
mockProvider.AddSearchResults(new[] { topNode1 });

var mockProjectContextProvider =
IDependenciesGraphProjectContextProviderFactory.Implement(
projectPath, subTreeProviders: new[] { mockProvider });

var outputNodes = new HashSet<GraphNode>();
var mockGraphContext = IGraphContextFactory.ImplementSearchAsync(searchString,
outputNodes: outputNodes);

var provider = new TestableDependenciesGraphProvider(mockProjectContextProvider,
Mock.Of<SVsServiceProvider>(),
new IProjectThreadingServiceMock().JoinableTaskContext);

// Act
await provider.BeginGetGraphDataAsync(mockGraphContext);

// Assert
Assert.Equal(2, outputNodes.Count);

var outputArray = outputNodes.ToArray();
// check if top level nodes got CodeNodeCategories.ProjectItem to make sure
// graph matched them back with IVsHierarchy nodes
Assert.True(outputArray[0].HasCategory(CodeNodeCategories.ProjectItem));
Assert.Equal(1, outputArray[0].OutgoingLinkCount);
Assert.Equal(@"c:/myproject/mytopnodeitemspec", outputArray[0].Id.GetNestedValueByName<Uri>(CodeGraphNodeIdName.File).AbsolutePath);
Assert.False(outputArray[1].HasCategory(CodeNodeCategories.ProjectItem));
}

[Fact]
public async Task DependenciesGraphProvider_TrackChangesAsync()
{
Expand Down
Loading