Browse Source

WaitForComponent helper + scrub boilerplate comments

Replaces the brittle root.GetVisualDescendants().OfType<T>().Single() / .First()
pattern with a new WaitForComponent<T>() extension that polls until the requested
control is in the visual tree, then returns it. Avalonia.Headless tests routinely
queried the visual tree before lazily-templated panes (DataGrid, dock content)
had materialised, surfacing as intermittent 'Sequence contains no elements'
failures across the suite.

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 2 months ago
parent
commit
595faf16b8
  1. 3
      ILSpy.Tests/AssemblyList/AssemblyTreeContextMenuTests.cs
  2. 46
      ILSpy.Tests/AssemblyList/AssemblyTreeTests.cs
  3. 7
      ILSpy.Tests/AssemblyList/RemoveAssemblyContextMenuTests.cs
  4. 3
      ILSpy.Tests/Commands/CommandLineArgumentsTests.cs
  5. 21
      ILSpy.Tests/Commands/HelpCommandTests.cs
  6. 6
      ILSpy.Tests/ContextMenus/DecompileInNewViewTests.cs
  7. 39
      ILSpy.Tests/Editor/DecompilerViewTests.cs
  8. 2
      ILSpy.Tests/MainWindow/MainMenuTests.cs
  9. 6
      ILSpy.Tests/MainWindow/MainWindowTests.cs
  10. 8
      ILSpy.Tests/Navigation/BrowseBackForwardCommandTests.cs
  11. 23
      ILSpy.Tests/Navigation/NavigationTests.cs
  12. 8
      ILSpy.Tests/Options/ApiVisibilityFilterTests.cs

3
ILSpy.Tests/AssemblyList/AssemblyTreeContextMenuTests.cs

@ -52,7 +52,6 @@ public class AssemblyTreeContextMenuTests @@ -52,7 +52,6 @@ public class AssemblyTreeContextMenuTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
// Assert — TreeGrid carries a ContextMenu. (The menu may be empty if no entries are
@ -75,11 +74,9 @@ public class AssemblyTreeContextMenuTests @@ -75,11 +74,9 @@ public class AssemblyTreeContextMenuTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
var pane = await window.WaitForComponent<AssemblyListPane>();
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// select assemblyNode
vm.AssemblyTreeModel.SelectNode(assemblyNode);
TextViewContext? executionContext = null;

46
ILSpy.Tests/AssemblyList/AssemblyTreeTests.cs

@ -61,7 +61,6 @@ public class AssemblyTreeTests @@ -61,7 +61,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
// Act — pick CoreLib (always ships localised error-message tables), expand it.
@ -89,7 +88,6 @@ public class AssemblyTreeTests @@ -89,7 +88,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
// Act — locate the realised DataGrid inside the AssemblyListPane.
@ -112,7 +110,6 @@ public class AssemblyTreeTests @@ -112,7 +110,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
@ -153,7 +150,6 @@ public class AssemblyTreeTests @@ -153,7 +150,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var tempDir = Path.Combine(Path.GetTempPath(), "ILSpy.Tests", System.Guid.NewGuid().ToString("N"));
@ -174,7 +170,6 @@ public class AssemblyTreeTests @@ -174,7 +170,6 @@ public class AssemblyTreeTests
var openCommand = registry.Commands
.Single(c => c.Metadata.Header == nameof(Resources._Open))
.CreateExport().Value;
// execute openCommand
openCommand.Execute(zipPath);
await Waiters.WaitForAsync(() =>
@ -212,7 +207,6 @@ public class AssemblyTreeTests @@ -212,7 +207,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var coreLibName = typeof(object).Assembly.GetName().Name!;
@ -247,7 +241,6 @@ public class AssemblyTreeTests @@ -247,7 +241,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -279,7 +272,6 @@ public class AssemblyTreeTests @@ -279,7 +272,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -312,7 +304,6 @@ public class AssemblyTreeTests @@ -312,7 +304,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -349,7 +340,6 @@ public class AssemblyTreeTests @@ -349,7 +340,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -375,7 +365,6 @@ public class AssemblyTreeTests @@ -375,7 +365,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -405,7 +394,6 @@ public class AssemblyTreeTests @@ -405,7 +394,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -459,7 +447,6 @@ public class AssemblyTreeTests @@ -459,7 +447,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var coreLibDir = System.IO.Path.GetDirectoryName(typeof(object).Assembly.Location)!;
@ -473,7 +460,6 @@ public class AssemblyTreeTests @@ -473,7 +460,6 @@ public class AssemblyTreeTests
var openCommand = registry.Commands
.Single(c => c.Metadata.Header == nameof(Resources._Open))
.CreateExport().Value;
// execute openCommand
openCommand.Execute(mscorlibPath);
await Waiters.WaitForAsync(() =>
@ -523,7 +509,6 @@ public class AssemblyTreeTests @@ -523,7 +509,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -561,7 +546,6 @@ public class AssemblyTreeTests @@ -561,7 +546,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
@ -602,7 +586,6 @@ public class AssemblyTreeTests @@ -602,7 +586,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var newAsmPath = typeof(System.Net.Http.HttpClient).Assembly.Location;
@ -610,7 +593,6 @@ public class AssemblyTreeTests @@ -610,7 +593,6 @@ public class AssemblyTreeTests
var openCommand = registry.Commands
.Single(c => c.Metadata.Header == nameof(Resources._Open))
.CreateExport().Value;
// execute openCommand
openCommand.Execute(newAsmPath);
await Waiters.WaitForAsync(() =>
@ -634,7 +616,6 @@ public class AssemblyTreeTests @@ -634,7 +616,6 @@ public class AssemblyTreeTests
var methodNode = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "CancelPendingRequests");
// select methodNode
vm.AssemblyTreeModel.SelectNode(methodNode);
await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -667,7 +648,6 @@ public class AssemblyTreeTests @@ -667,7 +648,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var newAsmPath = typeof(System.Net.Http.HttpClient).Assembly.Location;
@ -675,7 +655,6 @@ public class AssemblyTreeTests @@ -675,7 +655,6 @@ public class AssemblyTreeTests
var openCommand = registry.Commands
.Single(c => c.Metadata.Header == nameof(Resources._Open))
.CreateExport().Value;
// execute openCommand
openCommand.Execute(newAsmPath);
await Waiters.WaitForAsync(() =>
@ -693,7 +672,6 @@ public class AssemblyTreeTests @@ -693,7 +672,6 @@ public class AssemblyTreeTests
var methodNode = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "CancelPendingRequests");
// select methodNode
vm.AssemblyTreeModel.SelectNode(methodNode);
await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -734,7 +712,6 @@ public class AssemblyTreeTests @@ -734,7 +712,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var newAsmPath = typeof(System.Net.Http.HttpClient).Assembly.Location;
@ -745,7 +722,6 @@ public class AssemblyTreeTests @@ -745,7 +722,6 @@ public class AssemblyTreeTests
var openCommand = registry.Commands
.Single(c => c.Metadata.Header == nameof(Resources._Open))
.CreateExport().Value;
// execute openCommand
openCommand.Execute(newAsmPath);
await Waiters.WaitForAsync(() =>
@ -777,7 +753,6 @@ public class AssemblyTreeTests @@ -777,7 +753,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var enumerable = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
@ -787,23 +762,18 @@ public class AssemblyTreeTests @@ -787,23 +762,18 @@ public class AssemblyTreeTests
var ns = (NamespaceTreeNode)enumerable.Parent!;
ns.EnsureLazyChildren();
ns.IsExpanded = true;
// expand ns
var asm = (AssemblyTreeNode)ns.Parent!;
// expand asm
asm.IsExpanded = true;
foreach (var child in ns.Children.OfType<TypeTreeNode>())
{
child.EnsureLazyChildren();
child.IsExpanded = true;
// expand child
}
var pane = await window.WaitForComponent<AssemblyListPane>();
var grid = await pane.WaitForComponent<DataGrid>();
// select enumerable
vm.AssemblyTreeModel.SelectNode(enumerable);
// wait for the predicate
await Waiters.WaitForAsync(() => ReferenceEquals(vm.AssemblyTreeModel.SelectedItem, enumerable));
for (int i = 0; i < 8; i++)
{
@ -812,7 +782,7 @@ public class AssemblyTreeTests @@ -812,7 +782,7 @@ public class AssemblyTreeTests
}
grid.UpdateLayout();
var scrollViewer = grid.GetVisualDescendants().OfType<ScrollViewer>().Single();
var scrollViewer = await grid.WaitForComponent<ScrollViewer>();
(scrollViewer.Extent.Height - scrollViewer.Viewport.Height).Should().BeGreaterThan(50,
"the grid must have something to scroll for this test to be meaningful");
scrollViewer.Offset = new Vector(scrollViewer.Offset.X, 50);
@ -863,11 +833,9 @@ public class AssemblyTreeTests @@ -863,11 +833,9 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var probe = new SaveProbeNode();
// select probe
vm.AssemblyTreeModel.SelectNode(probe);
// Act — fire the Save Code main-menu command.
@ -875,7 +843,6 @@ public class AssemblyTreeTests @@ -875,7 +843,6 @@ public class AssemblyTreeTests
var saveCmd = registry.Commands
.Single(c => c.Metadata.Header == nameof(Resources._SaveCode))
.CreateExport().Value;
// execute saveCmd
saveCmd.Execute(null);
// Assert — probe's Save() ran.
@ -905,7 +872,6 @@ public class AssemblyTreeTests @@ -905,7 +872,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
@ -914,7 +880,6 @@ public class AssemblyTreeTests @@ -914,7 +880,6 @@ public class AssemblyTreeTests
typeNode.IsExpanded = true;
var method = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "AsEnumerable");
// select method
vm.AssemblyTreeModel.SelectNode(method);
await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -959,15 +924,12 @@ public class AssemblyTreeTests @@ -959,15 +924,12 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var sacrificialName = typeof(System.Linq.Enumerable).Assembly.GetName().Name!;
var survivorName = typeof(object).Assembly.GetName().Name!;
var sacrificialNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>(sacrificialName);
// select sacrificialNode
vm.AssemblyTreeModel.SelectNode(sacrificialNode);
// wait for the predicate
await Waiters.WaitForAsync(() => ReferenceEquals(vm.AssemblyTreeModel.SelectedItem, sacrificialNode));
var pane = await window.WaitForComponent<AssemblyListPane>();
@ -1013,7 +975,6 @@ public class AssemblyTreeTests @@ -1013,7 +975,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
vm.AssemblyTreeModel.AssemblyList!.Count.Should().BeGreaterThan(0);
@ -1023,11 +984,9 @@ public class AssemblyTreeTests @@ -1023,11 +984,9 @@ public class AssemblyTreeTests
.Single(c => c.Metadata.Header == nameof(Resources.ClearAssemblyList))
.CreateExport().Value;
clearCmd.CanExecute(null).Should().BeTrue("non-empty list must enable Clear");
// execute clearCmd
clearCmd.Execute(null);
// Assert — the list goes to zero entries.
// wait for the predicate
await Waiters.WaitForAsync(() => vm.AssemblyTreeModel.AssemblyList!.Count == 0);
vm.AssemblyTreeModel.AssemblyList!.Count.Should().Be(0);
}
@ -1044,7 +1003,6 @@ public class AssemblyTreeTests @@ -1044,7 +1003,6 @@ public class AssemblyTreeTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var brokenPath = System.IO.Path.Combine(
@ -1060,7 +1018,6 @@ public class AssemblyTreeTests @@ -1060,7 +1018,6 @@ public class AssemblyTreeTests
var broken = vm.AssemblyTreeModel.AssemblyList!.GetAssemblies()
.First(a => string.Equals(a.FileName, brokenPath, System.StringComparison.OrdinalIgnoreCase));
// GetLoadResultAsync rethrows the load failure; HasLoadError is the safe probe.
// wait for the predicate
await Waiters.WaitForAsync(() => broken.HasLoadError);
var validBefore = vm.AssemblyTreeModel.AssemblyList!.GetAssemblies()
@ -1075,7 +1032,6 @@ public class AssemblyTreeTests @@ -1075,7 +1032,6 @@ public class AssemblyTreeTests
.Single(c => c.Metadata.Header == nameof(Resources._RemoveAssembliesWithLoadErrors))
.CreateExport().Value;
cmd.CanExecute(null).Should().BeTrue("a broken entry must enable the command");
// execute cmd
cmd.Execute(null);
await Waiters.WaitForAsync(() =>

7
ILSpy.Tests/AssemblyList/RemoveAssemblyContextMenuTests.cs

@ -71,7 +71,6 @@ public class RemoveAssemblyContextMenuTests @@ -71,7 +71,6 @@ public class RemoveAssemblyContextMenuTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var registry = AppComposition.Current.GetExport<ContextMenuEntryRegistry>();
var removeEntry = registry.Entries
@ -110,7 +109,6 @@ public class RemoveAssemblyContextMenuTests @@ -110,7 +109,6 @@ public class RemoveAssemblyContextMenuTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var registry = AppComposition.Current.GetExport<ContextMenuEntryRegistry>();
var removeEntry = registry.Entries
@ -145,14 +143,11 @@ public class RemoveAssemblyContextMenuTests @@ -145,14 +143,11 @@ public class RemoveAssemblyContextMenuTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
// wait for the predicate
await Waiters.WaitForAsync(
() => window.GetVisualDescendants().OfType<AssemblyListPane>().Any());
var pane = window.GetVisualDescendants().OfType<AssemblyListPane>().Single();
var pane = await window.WaitForComponent<AssemblyListPane>();
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// select assemblyNode
vm.AssemblyTreeModel.SelectNode(assemblyNode);
var registry = AppComposition.Current.GetExport<ContextMenuEntryRegistry>();

3
ILSpy.Tests/Commands/CommandLineArgumentsTests.cs

@ -46,7 +46,6 @@ public class CommandLineArgumentsTests @@ -46,7 +46,6 @@ public class CommandLineArgumentsTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
var languageService = AppComposition.Current.GetExport<LanguageService>();
languageService.CurrentLanguage.Name.Should().NotBe("IL", "baseline must differ from the value we'll assert");
@ -72,7 +71,6 @@ public class CommandLineArgumentsTests @@ -72,7 +71,6 @@ public class CommandLineArgumentsTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var args = CommandLineArguments.Create(new[] { "--navigateto", "T:System.Linq.Enumerable" });
@ -98,7 +96,6 @@ public class CommandLineArgumentsTests @@ -98,7 +96,6 @@ public class CommandLineArgumentsTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
// clear selection
vm.AssemblyTreeModel.SelectedItems.Clear();

21
ILSpy.Tests/Commands/HelpCommandTests.cs

@ -55,7 +55,6 @@ public class HelpCommandTests @@ -55,7 +55,6 @@ public class HelpCommandTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
var registry = AppComposition.Current.GetExport<MainMenuCommandRegistry>();
@ -68,7 +67,6 @@ public class HelpCommandTests @@ -68,7 +67,6 @@ public class HelpCommandTests
// Act — fire the About command.
aboutCmd.Execute(null);
// execute aboutCmd
// Assert — a new DecompilerTabPageModel landed in the document dock, titled "About",
// containing the version line and the MIT License mention from the embedded blurb.
@ -95,7 +93,6 @@ public class HelpCommandTests @@ -95,7 +93,6 @@ public class HelpCommandTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
var registry = AppComposition.Current.GetExport<MainMenuCommandRegistry>();
@ -103,9 +100,7 @@ public class HelpCommandTests @@ -103,9 +100,7 @@ public class HelpCommandTests
.Single(c => c.Metadata.Header == nameof(Resources._About))
.CreateExport().Value;
var documents = ((ILSpyDockFactory)vm.DockWorkspace.Factory).Documents!;
// execute aboutCmd
aboutCmd.Execute(null);
// wait for the predicate
await Waiters.WaitForAsync(
() => documents.ActiveDockable is DecompilerTabPageModel { Text.Length: > 0 });
var aboutTab = (DecompilerTabPageModel)documents.ActiveDockable!;
@ -160,20 +155,16 @@ public class HelpCommandTests @@ -160,20 +155,16 @@ public class HelpCommandTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
var node = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// select node
vm.AssemblyTreeModel.SelectNode(node);
// wait for decompile to finish
await vm.DockWorkspace.WaitForDecompiledTextAsync();
// wait for the predicate
await Waiters.WaitForAsync(
() => window.GetVisualDescendants().OfType<DecompilerTextView>().Any());
// Act — locate the editor inside the realised DecompilerTextView.
var view = window.GetVisualDescendants().OfType<DecompilerTextView>().First();
var editor = view.GetVisualDescendants().OfType<AvaloniaEdit.TextEditor>().Single();
var view = await window.WaitForComponent<DecompilerTextView>();
var editor = await view.WaitForComponent<AvaloniaEdit.TextEditor>();
// Assert — the editor's hyperlink-click option is off.
editor.Options.RequireControlModifierForHyperlinkClick.Should().BeFalse(
@ -193,18 +184,14 @@ public class HelpCommandTests @@ -193,18 +184,14 @@ public class HelpCommandTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var method = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "AsEnumerable");
// select method
vm.AssemblyTreeModel.SelectNode(method);
// wait for decompile to finish
await vm.DockWorkspace.WaitForDecompiledTextAsync();
var decompilerTab = vm.DockWorkspace.ActiveDecompilerTab!;
var methodText = decompilerTab.Text;
@ -219,9 +206,7 @@ public class HelpCommandTests @@ -219,9 +206,7 @@ public class HelpCommandTests
.Single(c => c.Metadata.Header == nameof(Resources._About))
.CreateExport().Value;
var documents = ((ILSpyDockFactory)vm.DockWorkspace.Factory).Documents!;
// execute aboutCmd
aboutCmd.Execute(null);
// wait for the predicate
await Waiters.WaitForAsync(
() => documents.ActiveDockable is DecompilerTabPageModel { IsStaticContent: true });
var aboutTab = (DecompilerTabPageModel)documents.ActiveDockable!;
@ -238,7 +223,6 @@ public class HelpCommandTests @@ -238,7 +223,6 @@ public class HelpCommandTests
vm.DockWorkspace.NavigateBackCommand.CanExecute(null).Should().BeTrue();
// execute vm.DockWorkspace.NavigateBackCommand
vm.DockWorkspace.NavigateBackCommand.Execute(null);
// wait for the predicate
await Waiters.WaitForAsync(
() => ReferenceEquals(documents.ActiveDockable, decompilerTab));
@ -253,7 +237,6 @@ public class HelpCommandTests @@ -253,7 +237,6 @@ public class HelpCommandTests
vm.DockWorkspace.NavigateForwardCommand.CanExecute(null).Should().BeTrue();
// execute vm.DockWorkspace.NavigateForwardCommand
vm.DockWorkspace.NavigateForwardCommand.Execute(null);
// wait for the predicate
await Waiters.WaitForAsync(
() => ReferenceEquals(documents.ActiveDockable, aboutTab));

6
ILSpy.Tests/ContextMenus/DecompileInNewViewTests.cs

@ -67,7 +67,6 @@ public class DecompileInNewViewTests @@ -67,7 +67,6 @@ public class DecompileInNewViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
var registry = AppComposition.Current.GetExport<ContextMenuEntryRegistry>();
var entry = registry.Entries
@ -96,19 +95,15 @@ public class DecompileInNewViewTests @@ -96,19 +95,15 @@ public class DecompileInNewViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var firstMethod = typeNode.Children.OfType<MethodTreeNode>()
.Single(m => m.MethodDefinition.Name == "AsEnumerable");
var secondMethod = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "Empty");
// select firstMethod
vm.AssemblyTreeModel.SelectNode(firstMethod);
// wait for decompile to finish
var firstTab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
var registry = AppComposition.Current.GetExport<ContextMenuEntryRegistry>();
@ -128,7 +123,6 @@ public class DecompileInNewViewTests @@ -128,7 +123,6 @@ public class DecompileInNewViewTests
// shows AsEnumerable.
await Waiters.WaitForAsync(
() => (documents.VisibleDockables?.Count ?? 0) > initialCount);
// wait for decompile to finish
var newTab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
ReferenceEquals(newTab, firstTab).Should().BeFalse(
"a fresh decompiler tab must be created instead of reusing the existing one");

39
ILSpy.Tests/Editor/DecompilerViewTests.cs

@ -53,21 +53,17 @@ public class DecompilerViewTests @@ -53,21 +53,17 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var methodNode = typeNode.Children.OfType<MethodTreeNode>()
.Single(m => m.MethodDefinition.Name == "AsEnumerable");
methodNode.MethodDefinition.IsExtensionMethod.Should().BeTrue();
// Act — select the method node and wait for the decompile.
// select methodNode
vm.AssemblyTreeModel.SelectNode(methodNode);
// wait for decompile to finish
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
// Assert — signature + body fragments are present and the row centred in the tree.
@ -89,16 +85,13 @@ public class DecompilerViewTests @@ -89,16 +85,13 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// expand assemblyNode
assemblyNode.IsExpanded = true;
var refFolder = assemblyNode.Children.OfType<ReferenceFolderTreeNode>().Single();
// Act — select the References folder and wait for its decompile output.
// select refFolder
vm.AssemblyTreeModel.SelectNode(refFolder);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -120,7 +113,6 @@ public class DecompilerViewTests @@ -120,7 +113,6 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var coreLib = typeof(object).Assembly.GetName().Name!;
@ -128,7 +120,6 @@ public class DecompilerViewTests @@ -128,7 +120,6 @@ public class DecompilerViewTests
coreLib, "System", "System.Version");
// Act — select the type node, wait for the decompile.
// select typeNode
vm.AssemblyTreeModel.SelectNode(typeNode);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -148,19 +139,16 @@ public class DecompilerViewTests @@ -148,19 +139,16 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var coreLib = typeof(object).Assembly.GetName().Name!;
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
coreLib, "System", "System.Version");
// expand typeNode
typeNode.IsExpanded = true;
var propertyNode = typeNode.Children.OfType<PropertyTreeNode>()
.Single(p => p.PropertyDefinition.Name == "Major");
// Act — select the property, wait for the decompile.
// select propertyNode
vm.AssemblyTreeModel.SelectNode(propertyNode);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -178,19 +166,16 @@ public class DecompilerViewTests @@ -178,19 +166,16 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var coreLib = typeof(object).Assembly.GetName().Name!;
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
coreLib, "System", "System.Math");
// expand typeNode
typeNode.IsExpanded = true;
var fieldNode = typeNode.Children.OfType<FieldTreeNode>()
.Single(f => f.FieldDefinition.Name == "PI");
// Act — select the field, wait for the decompile.
// select fieldNode
vm.AssemblyTreeModel.SelectNode(fieldNode);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -208,19 +193,16 @@ public class DecompilerViewTests @@ -208,19 +193,16 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var coreLib = typeof(object).Assembly.GetName().Name!;
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
coreLib, "System", "System.AppDomain");
// expand typeNode
typeNode.IsExpanded = true;
var eventNode = typeNode.Children.OfType<EventTreeNode>()
.Single(e => e.EventDefinition.Name == "ProcessExit");
// Act — select the event, wait for the decompile.
// select eventNode
vm.AssemblyTreeModel.SelectNode(eventNode);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -238,7 +220,6 @@ public class DecompilerViewTests @@ -238,7 +220,6 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var coreLib = typeof(object).Assembly.GetName().Name!;
@ -246,7 +227,6 @@ public class DecompilerViewTests @@ -246,7 +227,6 @@ public class DecompilerViewTests
coreLib, "System.Runtime.Versioning");
// Act — select the namespace, wait for the decompile.
// select namespaceNode
vm.AssemblyTreeModel.SelectNode(namespaceNode);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -266,7 +246,6 @@ public class DecompilerViewTests @@ -266,7 +246,6 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
// Act 1 — fire OpenCommand on a new path. OpenCommand selects the new node before its
@ -276,7 +255,6 @@ public class DecompilerViewTests @@ -276,7 +255,6 @@ public class DecompilerViewTests
var openCommand = registry.Commands
.Single(c => c.Metadata.Header == nameof(Resources._Open))
.CreateExport().Value;
// execute openCommand
openCommand.Execute(newAsmPath);
await Waiters.WaitForAsync(() =>
@ -290,7 +268,6 @@ public class DecompilerViewTests @@ -290,7 +268,6 @@ public class DecompilerViewTests
// Assert — once Text is rich, the tab title catches up. Sanity-check the form is rich
// (otherwise the test isn't exercising the late-update path).
// wait for the predicate
await Waiters.WaitForAsync(() => string.Equals(tab.Title, node.Text?.ToString(), System.StringComparison.Ordinal));
node.Text!.ToString().Should().NotBe(node.LoadedAssembly.ShortName,
"the rich form (with version + tfm) must be available, otherwise the test isn't exercising the late-update path");
@ -309,11 +286,9 @@ public class DecompilerViewTests @@ -309,11 +286,9 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var firstNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// select firstNode
vm.AssemblyTreeModel.SelectNode(firstNode);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -324,7 +299,6 @@ public class DecompilerViewTests @@ -324,7 +299,6 @@ public class DecompilerViewTests
// Act — kick off a second decompile and observe Title/Text changes throughout.
var coreLib = typeof(object).Assembly.GetName().Name!;
var second = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(coreLib, "System", "System.Version");
// select second
vm.AssemblyTreeModel.SelectNode(second);
await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -359,12 +333,10 @@ public class DecompilerViewTests @@ -359,12 +333,10 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var asEnumerable = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "AsEnumerable");
@ -392,12 +364,10 @@ public class DecompilerViewTests @@ -392,12 +364,10 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var asEnumerable = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "AsEnumerable");
@ -409,7 +379,6 @@ public class DecompilerViewTests @@ -409,7 +379,6 @@ public class DecompilerViewTests
vm.AssemblyTreeModel.SelectedItems.Add(asEnumerable);
vm.AssemblyTreeModel.SelectedItems.Add(empty);
// wait for decompile to finish
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
// Assert — both names AND a body-fragment from one of them confirm both bodies
@ -429,16 +398,13 @@ public class DecompilerViewTests @@ -429,16 +398,13 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// Act — select the assembly node, wait for the decompile.
// select assemblyNode
vm.AssemblyTreeModel.SelectNode(assemblyNode);
// wait for decompile to finish
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
// Assert — every documented header line and at least one assembly attribute land.
@ -462,11 +428,9 @@ public class DecompilerViewTests @@ -462,11 +428,9 @@ public class DecompilerViewTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// select assemblyNode
vm.AssemblyTreeModel.SelectNode(assemblyNode);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -475,10 +439,9 @@ public class DecompilerViewTests @@ -475,10 +439,9 @@ public class DecompilerViewTests
var xml = "<root>\n <child attr=\"v\">\n text\n </child>\n <other>\n </other>\n</root>";
var bytes = System.Text.Encoding.UTF8.GetBytes(xml);
tab.CurrentNode = new XmlResourceEntryNode("test.xml", () => new System.IO.MemoryStream(bytes));
// wait for the predicate
await Waiters.WaitForAsync(() => tab.SyntaxExtension == ".xml" && tab.Text.Contains("<root>"));
var view = window.GetVisualDescendants().OfType<DecompilerTextView>().Single();
var view = await window.WaitForComponent<DecompilerTextView>();
// Drain the layout so ApplyDocument's PropertyChanged handler has executed.
for (int i = 0; i < 5; i++)
{

2
ILSpy.Tests/MainWindow/MainMenuTests.cs

@ -64,7 +64,7 @@ public class MainMenuTests @@ -64,7 +64,7 @@ public class MainMenuTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var menu = window.GetVisualDescendants().OfType<Menu>().First();
var menu = await window.WaitForComponent<Menu>();
await Waiters.WaitForAsync(() =>
menu.Items.OfType<MenuItem>().Any(m => (string?)m.Tag == nameof(Resources._File))
&& menu.Items.OfType<MenuItem>().Single(m => (string?)m.Tag == nameof(Resources._File))

6
ILSpy.Tests/MainWindow/MainWindowTests.cs

@ -66,9 +66,8 @@ public class MainWindowTests @@ -66,9 +66,8 @@ public class MainWindowTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
// wait for the predicate
await Waiters.WaitForAsync(() => window.GetVisualDescendants().OfType<AssemblyListPane>().Any());
var pane = window.GetVisualDescendants().OfType<AssemblyListPane>().Single();
var pane = await window.WaitForComponent<AssemblyListPane>();
// Assert — visible with positive width and height.
pane.IsVisible.Should().BeTrue();
@ -137,7 +136,6 @@ public class MainWindowTests @@ -137,7 +136,6 @@ public class MainWindowTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var service = AppComposition.Current.GetExport<TaskbarProgressService>();
@ -147,9 +145,7 @@ public class MainWindowTests @@ -147,9 +145,7 @@ public class MainWindowTests
// Act — trigger a decompile.
var node = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
// select node
vm.AssemblyTreeModel.SelectNode(node);
// wait for decompile to finish
await vm.DockWorkspace.WaitForDecompiledTextAsync();
service.StateChanged -= Observe;

8
ILSpy.Tests/Navigation/BrowseBackForwardCommandTests.cs

@ -82,12 +82,10 @@ public class BrowseBackForwardCommandTests @@ -82,12 +82,10 @@ public class BrowseBackForwardCommandTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var firstMethod = typeNode.Children.OfType<MethodTreeNode>()
.Single(m => m.MethodDefinition.Name == "AsEnumerable");
@ -95,7 +93,7 @@ public class BrowseBackForwardCommandTests @@ -95,7 +93,7 @@ public class BrowseBackForwardCommandTests
.First(m => m.MethodDefinition.Name == "Empty");
// Locate the View > Back menu item.
var menu = window.GetVisualDescendants().OfType<Menu>().First();
var menu = await window.WaitForComponent<Menu>();
var viewMenu = menu.Items.OfType<MenuItem>()
.Single(m => (string?)m.Tag == nameof(Resources._View));
// expand the View menu so its child items are realised.
@ -109,11 +107,9 @@ public class BrowseBackForwardCommandTests @@ -109,11 +107,9 @@ public class BrowseBackForwardCommandTests
"with no navigation history, BrowseBack must report CanExecute=false");
// Build history: select two methods with a delay so they record as separate entries.
// select firstMethod
vm.AssemblyTreeModel.SelectNode(firstMethod);
await vm.DockWorkspace.WaitForDecompiledTextAsync();
await Task.Delay(600);
// select secondMethod
vm.AssemblyTreeModel.SelectNode(secondMethod);
await vm.DockWorkspace.WaitForDecompiledTextAsync();
@ -136,7 +132,7 @@ public class BrowseBackForwardCommandTests @@ -136,7 +132,7 @@ public class BrowseBackForwardCommandTests
// Arrange — boot, locate the View menu, wait for both nav items to materialise.
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var menu = window.GetVisualDescendants().OfType<Menu>().First();
var menu = await window.WaitForComponent<Menu>();
var viewMenu = menu.Items.OfType<MenuItem>()
.Single(m => (string?)m.Tag == nameof(Resources._View));
viewMenu.Open();

23
ILSpy.Tests/Navigation/NavigationTests.cs

@ -49,12 +49,10 @@ public class NavigationTests @@ -49,12 +49,10 @@ public class NavigationTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var firstMethod = typeNode.Children.OfType<MethodTreeNode>()
.Single(m => m.MethodDefinition.Name == "AsEnumerable");
@ -62,10 +60,7 @@ public class NavigationTests @@ -62,10 +60,7 @@ public class NavigationTests
.First(m => m.MethodDefinition.Name == "Empty");
// Act 1 — select AsEnumerable, wait for it to decompile.
// select firstMethod
// select firstMethod
vm.AssemblyTreeModel.SelectNode(firstMethod);
// wait for decompile to finish
var firstTab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
firstTab.Text.Should().Contain("AsEnumerable");
@ -74,12 +69,8 @@ public class NavigationTests @@ -74,12 +69,8 @@ public class NavigationTests
await Task.Delay(600);
// Act 2 — select Empty, wait for its decompile.
// select secondMethod
// select secondMethod
vm.AssemblyTreeModel.SelectNode(secondMethod);
// wait for the predicate
await Waiters.WaitForAsync(() => ReferenceEquals(vm.AssemblyTreeModel.SelectedItem, secondMethod));
// wait for decompile to finish
var secondTab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
secondTab.Text.Should().Contain("Empty");
@ -90,9 +81,7 @@ public class NavigationTests @@ -90,9 +81,7 @@ public class NavigationTests
// Assert — selection restores to AsEnumerable, the document re-decompiles to its body,
// and the row is centred back into view.
// wait for the predicate
await Waiters.WaitForAsync(() => ReferenceEquals(vm.AssemblyTreeModel.SelectedItem, firstMethod));
// wait for decompile to finish
var restoredTab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
restoredTab.Text.Should().Contain("AsEnumerable");
restoredTab.Text.Should().Contain("return source");
@ -112,12 +101,10 @@ public class NavigationTests @@ -112,12 +101,10 @@ public class NavigationTests
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
// wait for assemblies to load
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var typeNode = vm.AssemblyTreeModel.FindNode<TypeTreeNode>(
"System.Linq", "System.Linq", "System.Linq.Enumerable");
// expand typeNode
typeNode.IsExpanded = true;
var methodA = typeNode.Children.OfType<MethodTreeNode>()
.First(m => m.MethodDefinition.Name == "AsEnumerable");
@ -128,19 +115,13 @@ public class NavigationTests @@ -128,19 +115,13 @@ public class NavigationTests
// Act 1 — three distinct selections with >0.6s gaps so each lands as its own entry on
// the back stack (NavigationHistory collapses sub-0.5s rapid succession into one entry).
// select methodA
vm.AssemblyTreeModel.SelectNode(methodA);
// wait for decompile to finish
await vm.DockWorkspace.WaitForDecompiledTextAsync();
await Task.Delay(600);
// select methodB
vm.AssemblyTreeModel.SelectNode(methodB);
// wait for decompile to finish
await vm.DockWorkspace.WaitForDecompiledTextAsync();
await Task.Delay(600);
// select methodC
vm.AssemblyTreeModel.SelectNode(methodC);
// wait for decompile to finish
await vm.DockWorkspace.WaitForDecompiledTextAsync();
// Act 2 — open the Back SplitButton's flyout. The Opening handler populates the menu
@ -150,8 +131,6 @@ public class NavigationTests @@ -150,8 +131,6 @@ public class NavigationTests
var flyout = (MenuFlyout)backSplit.Flyout!;
// open flyout on backSplit
flyout.ShowAt(backSplit);
// wait for the predicate
// wait for the predicate
await Waiters.WaitForAsync(() => flyout.Items.OfType<MenuItem>().Count() >= 2);
// Assert 1 — newest-first ordering: index 0 is the immediate previous selection
@ -166,8 +145,6 @@ public class NavigationTests @@ -166,8 +145,6 @@ public class NavigationTests
// Act 3 — multi-step jump: clicking methodA pops two entries off the back stack in one go.
items[1].Command!.Execute(items[1].CommandParameter);
// wait for the predicate
// wait for the predicate
await Waiters.WaitForAsync(() => ReferenceEquals(vm.AssemblyTreeModel.SelectedItem, methodA));
// Assert 2 — the two displaced entries (methodC, methodB) are now on the forward stack,

8
ILSpy.Tests/Options/ApiVisibilityFilterTests.cs

@ -177,8 +177,8 @@ public class ApiVisibilityFilterTests @@ -177,8 +177,8 @@ public class ApiVisibilityFilterTests
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1);
await Waiters.WaitForAsync(
() => window.GetVisualDescendants().OfType<AssemblyListPane>().Any());
var pane = window.GetVisualDescendants().OfType<AssemblyListPane>().Single();
var grid = pane.GetVisualDescendants().OfType<DataGrid>().Single();
var pane = await window.WaitForComponent<AssemblyListPane>();
var grid = await pane.WaitForComponent<DataGrid>();
// Force any pending DataContext propagation so the initial HierarchicalModel is set.
var settings = AppComposition.Current.GetExport<SettingsService>().SessionSettings.LanguageSettings;
@ -220,8 +220,8 @@ public class ApiVisibilityFilterTests @@ -220,8 +220,8 @@ public class ApiVisibilityFilterTests
var nonPublicMethod = stringType.Children.OfType<MethodTreeNode>().First(m => !m.IsPublicAPI);
await Waiters.WaitForAsync(() => window.GetVisualDescendants().OfType<AssemblyListPane>().Any());
var pane = window.GetVisualDescendants().OfType<AssemblyListPane>().Single();
var grid = pane.GetVisualDescendants().OfType<DataGrid>().Single();
var pane = await window.WaitForComponent<AssemblyListPane>();
var grid = await pane.WaitForComponent<DataGrid>();
// Selecting each node scrolls it into view; that's how the row's TextBlock realises.
vm.AssemblyTreeModel.SelectNode(publicMethod);

Loading…
Cancel
Save