From 96016893d1854c386da1ccb7feddce0f580a1447 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 1 May 2026 19:28:42 +0200 Subject: [PATCH] Tests for MemberReferenceTreeNode + ExportedTypeTreeNode icons Assisted-by: Claude:claude-opus-4-7:Claude Code Assisted-by: Claude:claude-opus-4-7:Claude Code --- ILSpy.Tests/AssemblyList/AssemblyTreeTests.cs | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/ILSpy.Tests/AssemblyList/AssemblyTreeTests.cs b/ILSpy.Tests/AssemblyList/AssemblyTreeTests.cs index 8735a7d88..b33bccf3c 100644 --- a/ILSpy.Tests/AssemblyList/AssemblyTreeTests.cs +++ b/ILSpy.Tests/AssemblyList/AssemblyTreeTests.cs @@ -109,6 +109,103 @@ public class AssemblyTreeTests typesNode.Children.Should().Contain(c => c is TypeReferenceTreeNode); } + [AvaloniaTest] + public async Task Member_Reference_Node_Uses_Method_Or_Field_Overlay_Icon() + { + var window = AppComposition.Current.GetExport(); + window.Show(); + var vm = (MainWindowViewModel)window.DataContext!; + await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3); + + var assemblyNode = vm.AssemblyTreeModel.FindNode("System.Linq"); + assemblyNode.EnsureLazyChildren(); + var refFolder = assemblyNode.Children.OfType().Single(); + refFolder.EnsureLazyChildren(); + + // Walk every reference's ReferencedTypes subtree until we find a TypeRef that + // has at least one MemberReference. System.Linq imports plenty (e.g. delegates, + // Func ctors) so this should always succeed. + MemberReferenceTreeNode? memberRefNode = null; + foreach (var refNode in refFolder.Children.OfType()) + { + refNode.EnsureLazyChildren(); + var typesNode = refNode.Children.OfType().FirstOrDefault(); + if (typesNode == null) + continue; + typesNode.EnsureLazyChildren(); + foreach (var typeRef in typesNode.Children.OfType()) + { + typeRef.EnsureLazyChildren(); + memberRefNode = typeRef.Children.OfType().FirstOrDefault(); + if (memberRefNode != null) + break; + } + if (memberRefNode != null) + break; + } + + ((object?)memberRefNode).Should().NotBeNull( + "at least one TypeRef under System.Linq's references must have member references"); + memberRefNode!.Icon.Should().BeOneOf(global::ILSpy.Images.Images.MethodReference, + global::ILSpy.Images.Images.FieldReference); + memberRefNode.Text.ToString().Should().NotBeNullOrWhiteSpace(); + } + + [AvaloniaTest] + public async Task Exported_Type_Node_Uses_Export_Overlay_Icon() + { + var window = AppComposition.Current.GetExport(); + window.Show(); + var vm = (MainWindowViewModel)window.DataContext!; + await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3); + + // `mscorlib` is the canonical type-forwarder facade: it reports ExportedTypes that + // resolve to System.Private.CoreLib. Open it explicitly so the test fixture has a + // loaded forwarder regardless of what the default startup list includes. + var coreLibDir = System.IO.Path.GetDirectoryName(typeof(object).Assembly.Location)!; + var mscorlibPath = System.IO.Path.Combine(coreLibDir, "mscorlib.dll"); + if (!System.IO.File.Exists(mscorlibPath)) + { + Assert.Inconclusive($"mscorlib.dll not present next to System.Private.CoreLib at {coreLibDir} — runtime layout differs."); + return; + } + var registry = AppComposition.Current.GetExport(); + var openCommand = registry.Commands + .Single(c => c.Metadata.Header == nameof(Resources._Open)) + .CreateExport().Value; + openCommand.Execute(mscorlibPath); + + await Waiters.WaitForAsync(() => + vm.AssemblyTreeModel.AssemblyList!.GetAssemblies().Any(a => + string.Equals(a.FileName, mscorlibPath, System.StringComparison.OrdinalIgnoreCase))); + var loaded = vm.AssemblyTreeModel.AssemblyList!.GetAssemblies() + .First(a => string.Equals(a.FileName, mscorlibPath, System.StringComparison.OrdinalIgnoreCase)); + await loaded.GetLoadResultAsync(); + + var assemblyNode = vm.AssemblyTreeModel.FindNode(loaded.ShortName); + assemblyNode.EnsureLazyChildren(); + var refFolder = assemblyNode.Children.OfType().Single(); + refFolder.EnsureLazyChildren(); + + ExportedTypeTreeNode? exportedNode = null; + foreach (var refNode in refFolder.Children.OfType()) + { + refNode.EnsureLazyChildren(); + var typesNode = refNode.Children.OfType().FirstOrDefault(); + if (typesNode == null) + continue; + typesNode.EnsureLazyChildren(); + exportedNode = typesNode.Children.OfType().FirstOrDefault(); + if (exportedNode != null) + break; + } + + ((object?)exportedNode).Should().NotBeNull( + "mscorlib must forward types to System.Private.CoreLib via ExportedType rows"); + exportedNode!.Icon.Should().BeSameAs(global::ILSpy.Images.Images.ExportedType); + exportedNode.Text.ToString().Should().NotBeNullOrWhiteSpace(); + } + [AvaloniaTest] public async Task Expanding_Assembly_Reference_Reveals_Transitive_References() {