using YKanBan.Search; namespace YKanBan.Tests.Search; /// /// Structural comparer for search AST nodes, used by assertions only. The /// AST records compare by reference for their Terms collections by design /// (see the YYC MARK note in SearchNodes.cs), so tests provide equality /// explicitly. /// public sealed class SearchNodeComparer : IEqualityComparer { /// Shared comparer instance. public static SearchNodeComparer Instance { get; } = new(); /// Determines structural equality of two nodes. public bool Equals(SearchNode? x, SearchNode? y) { if (ReferenceEquals(x, y)) { return true; } if (x is null || y is null || x.GetType() != y.GetType()) { return false; } return (x, y) switch { (SearchNode.Or a, SearchNode.Or b) => SequencesEqual(a.Terms, b.Terms), (SearchNode.And a, SearchNode.And b) => SequencesEqual(a.Terms, b.Terms), (SearchNode.FreeText a, SearchNode.FreeText b) => a.Text == b.Text, (SearchNode.FieldText a, SearchNode.FieldText b) => a.Field == b.Field && a.Text == b.Text, (SearchNode.TagName a, SearchNode.TagName b) => a.Name == b.Name, (SearchNode.ColumnTitle a, SearchNode.ColumnTitle b) => a.Title == b.Title, (SearchNode.CardId a, SearchNode.CardId b) => a.Id == b.Id, _ => false, }; } /// Not supported: the comparer exists for assertions, not hashing. public int GetHashCode(SearchNode obj) => throw new NotSupportedException("Structural comparison for assertions only; hashing is not supported."); /// Order-sensitive element-wise comparison. private static bool SequencesEqual(IReadOnlyList x, IReadOnlyList y) { if (x.Count != y.Count) { return false; } return Enumerable.Zip(x, y, (a, b) => (a, b)).All(pair => Instance.Equals(pair.a, pair.b)); } }