public void TestGetTree() { var digest1 = new ManifestDigest(sha256New: "a"); var digest2 = new ManifestDigest(sha256New: "b"); _storeMock.Setup(x => x.GetPath(digest1)).Returns("fake/path"); _storeMock.Setup(x => x.GetPath(digest2)).Returns(() => null); var tree = _selectionsManager.GetTree(new Selections { InterfaceUri = new FeedUri("http://root/"), Implementations = { new ImplementationSelection { InterfaceUri = new FeedUri("http://root/"), ID = "a", ManifestDigest = digest1, Version = new ImplementationVersion("1.0"), Dependencies = { new Dependency { InterfaceUri = new FeedUri("http://dependency/") }, new Dependency { InterfaceUri = new FeedUri("http://missing/") } } }, new ImplementationSelection { InterfaceUri = new FeedUri("http://dependency/"), ID = "b", ManifestDigest = digest2, Version = new ImplementationVersion("2.0"), Dependencies = { new Dependency{ InterfaceUri = new FeedUri("http://root/") } } // Exercise cycle detection } } }); var node1 = new SelectionsTreeNode(new FeedUri("http://root/"), new ImplementationVersion("1.0"), "fake/path", parent: null); node1.ToString().Should().Be("- URI: http://root/\n Version: 1.0\n Path: fake/path"); var node2 = new SelectionsTreeNode(new FeedUri("http://dependency/"), new ImplementationVersion("2.0"), path: null, parent: node1); node2.ToString().Should().Be($" - URI: http://dependency/\n Version: 2.0\n {Resources.NotCached}"); var node3 = new SelectionsTreeNode(new FeedUri("http://missing/"), version: null, path: null, parent: node1); node3.ToString().Should().Be($" - URI: http://missing/\n {Resources.NoSelectedVersion}"); tree.Should().Equal(node1, node2, node3); }
/// <inheritdoc/> public NamedCollection <SelectionsTreeNode> GetTree(Selections selections) { #region Sanity checks if (selections == null) { throw new ArgumentNullException(nameof(selections)); } #endregion var visited = new HashSet <FeedUri>(); var result = new NamedCollection <SelectionsTreeNode>(); ImplementationSelection?TryGetImplementation(IInterfaceUri target) { try { return(selections[target.InterfaceUri]); } catch (KeyNotFoundException) { return(null); } } string?GetPath(ImplementationBase implementation) => implementation.LocalPath ?? (implementation.ID.StartsWith(ExternalImplementation.PackagePrefix) ? "(" + implementation.ID + ")" : _implementationStore.GetPath(implementation.ManifestDigest)); void AddNodes(IInterfaceUri target, SelectionsTreeNode?parent) { // Prevent infinite recursion if (visited.Contains(target.InterfaceUri)) { return; } visited.Add(target.InterfaceUri); var implementation = TryGetImplementation(target); var node = new SelectionsTreeNode( target.InterfaceUri, implementation?.Version, (implementation == null) ? null : GetPath(implementation), parent); result.Add(node); if (implementation == null) { return; } // Recurse into regular dependencies foreach (var dependency in implementation.Dependencies) { AddNodes(dependency, parent: node); } foreach (var command in implementation.Commands) { // Recurse into command dependencies foreach (var dependency in command.Dependencies) { AddNodes(dependency, parent: node); } // Recurse into runner dependency if (command.Runner != null) { AddNodes(command.Runner, parent: node); } } } AddNodes(selections, parent: null); return(result); }