namespace HrynCo.Common.Tests; using HrynCo.Common.Tree; using FluentAssertions; using Xunit; public sealed class FakeNode : ITreeNode { public required Guid Id { get; init; } public Guid? ParentId { get; init; } } public sealed class FakeNamedNode : ITreeNode, INameNode { public required string Name { get; init; } public required Guid Id { get; init; } public Guid? ParentId { get; init; } } public sealed class TreeUtilsTests { [Fact] public void CollectDescendants_ShouldReturnSelfAndAllChildren() { // Arrange var root = Guid.NewGuid(); var child1 = Guid.NewGuid(); var child2 = Guid.NewGuid(); var nodes = new List { new() { Id = root, ParentId = null }, new() { Id = child1, ParentId = root }, new() { Id = child2, ParentId = child1 } }; // Act var result = TreeUtils.CollectDescendants(root, nodes, Guid.Empty); // Assert result.Should().BeEquivalentTo(new[] { root, child1, child2 }); } [Fact] public void BuildBreadcrumb_ShouldReturnPathFromRootToNode() { // Arrange var root = Guid.NewGuid(); var child = Guid.NewGuid(); var grandchild = Guid.NewGuid(); var map = new Dictionary { [root] = new() { Id = root, ParentId = null, Name = "Root" }, [child] = new() { Id = child, ParentId = root, Name = "Child" }, [grandchild] = new() { Id = grandchild, ParentId = child, Name = "Grandchild" } }; // Act var result = TreeUtils.BuildBreadcrumb(grandchild, map); // Assert result.Should().BeEquivalentTo(new[] { new BreadcrumbNode(root, "Root"), new BreadcrumbNode(child, "Child"), new BreadcrumbNode(grandchild, "Grandchild") }, options => options.WithStrictOrdering()); } [Fact] public void CollectDescendants_ShouldReturnOnlyRootWhenThereAreNoChildren() { // Arrange var root = Guid.NewGuid(); // Act var result = TreeUtils.CollectDescendants(root, Array.Empty(), Guid.Empty); // Assert result.Should().BeEquivalentTo(new[] { root }); } [Fact] public void CollectDescendants_ShouldHandleCyclesWithoutRepeatingNodes() { // Arrange var root = Guid.NewGuid(); var child = Guid.NewGuid(); var nodes = new List { new() { Id = root, ParentId = child }, new() { Id = child, ParentId = root } }; // Act var result = TreeUtils.CollectDescendants(root, nodes, Guid.Empty); // Assert result.Should().BeEquivalentTo(new[] { root, child }); } [Fact] public void BuildBreadcrumb_ShouldReturnEmptyListWhenNodeIsMissing() { // Arrange var map = new Dictionary(); // Act var result = TreeUtils.BuildBreadcrumb(Guid.NewGuid(), map); // Assert result.Should().BeEmpty(); } }