File: Intermediate\IntermediateNodeWalkerTest.cs
Web Access
Project: src\src\Razor\src\Compiler\Microsoft.AspNetCore.Razor.Language\test\Microsoft.AspNetCore.Razor.Language.UnitTests.csproj (Microsoft.AspNetCore.Razor.Language.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
 
namespace Microsoft.AspNetCore.Razor.Language.Intermediate;
 
public class IntermediateNodeWalkerTest
{
    [Fact]
    public void IntermediateNodeWalker_Visit_TraversesEntireGraph()
    {
        // Arrange
        var walker = new DerivedIntermediateNodeWalker();
 
        var nodes = new IntermediateNode[]
        {
            new BasicIntermediateNode("Root"),
                new BasicIntermediateNode("Root->A"),
                new BasicIntermediateNode("Root->B"),
                    new BasicIntermediateNode("Root->B->1"),
                    new BasicIntermediateNode("Root->B->2"),
                new BasicIntermediateNode("Root->C"),
        };
 
        var builder = new DefaultRazorIntermediateNodeBuilder();
 
        builder.Push(nodes[0]);
        builder.Add(nodes[1]);
 
        builder.Push(nodes[2]);
        builder.Add(nodes[3]);
        builder.Add(nodes[4]);
        builder.Pop();
 
        builder.Add(nodes[5]);
 
        var root = builder.Pop();
 
        // Act
        walker.Visit(root);
 
        // Assert
        Assert.Equal(nodes, walker.Visited);
    }
 
    [Fact]
    public void IntermediateNodeWalker_Visit_SetsParentAndAncestors()
    {
        // Arrange
        var walker = new DerivedIntermediateNodeWalker();
 
        var nodes = new IntermediateNode[]
        {
            new BasicIntermediateNode("Root"),
                new BasicIntermediateNode("Root->A"),
                new BasicIntermediateNode("Root->B"),
                    new BasicIntermediateNode("Root->B->1"),
                    new BasicIntermediateNode("Root->B->2"),
                new BasicIntermediateNode("Root->C"),
        };
 
        var ancestors = new Dictionary<string, string[]>()
        {
            { "Root", [] },
            { "Root->A", ["Root"] },
            { "Root->B", ["Root"] },
            { "Root->B->1", ["Root->B", "Root"] },
            { "Root->B->2", ["Root->B", "Root"] },
            { "Root->C", ["Root"] },
        };
 
        walker.OnVisiting = (n, a) =>
        {
            var basicNode = Assert.IsType<BasicIntermediateNode>(n);
            var parent = a.Length > 0 ? (BasicIntermediateNode)a[0] : null;
 
            Assert.Equal(ancestors[basicNode.Name], a.Cast<BasicIntermediateNode>().Select(b => b.Name));
            Assert.Equal(ancestors[basicNode.Name].FirstOrDefault(), parent?.Name);
        };
 
        var builder = new DefaultRazorIntermediateNodeBuilder();
 
        builder.Push(nodes[0]);
        builder.Add(nodes[1]);
 
        builder.Push(nodes[2]);
        builder.Add(nodes[3]);
        builder.Add(nodes[4]);
        builder.Pop();
 
        builder.Add(nodes[5]);
 
        var root = builder.Pop();
 
        // Act & Assert
        walker.Visit(root);
    }
 
    private sealed class DerivedIntermediateNodeWalker : IntermediateNodeWalker
    {
        public List<IntermediateNode> Visited { get; } = [];
 
        public Action<IntermediateNode, IntermediateNode[]>? OnVisiting { get; set; }
 
        public override void VisitDefault(IntermediateNode node)
        {
            Visited.Add(node);
 
            OnVisiting?.Invoke(node, Ancestors.ToArray());
            base.VisitDefault(node);
        }
 
        public void VisitBasic(BasicIntermediateNode node)
        {
            VisitDefault(node);
        }
    }
 
    private sealed class BasicIntermediateNode(string name) : IntermediateNode
    {
        public string Name { get; } = name;
 
        public override IntermediateNodeCollection Children { get; } = [];
 
        public override void Accept(IntermediateNodeVisitor visitor)
            => ((DerivedIntermediateNodeWalker)visitor).VisitBasic(this);
 
        public override string ToString()
            => Name;
    }
}