| 1 | #nullable enable |
| 2 | |
| 3 | using CascadeIDE.Models.Intercom; |
| 4 | using CascadeIDE.Services.Intercom; |
| 5 | using Xunit; |
| 6 | |
| 7 | namespace CascadeIDE.Tests; |
| 8 | |
| 9 | public sealed class IntercomMessageCodeCorrespondenceTests |
| 10 | { |
| 11 | [Fact] |
| 12 | public void Find_OverlappingLineRanges_ReturnsOrdinal() |
| 13 | { |
| 14 | var lane = new[] |
| 15 | { |
| 16 | laneMessage(1, 0, attach("src/Foo.cs", 10, 20)), |
| 17 | laneMessage(2, 1, attach("src/Other.cs", 1, 5)), |
| 18 | }; |
| 19 | |
| 20 | var entries = IntercomMessageCodeCorrespondenceProjector.BuildInferred(lane); |
| 21 | var query = new IntercomCodeRefQuery("src/Foo.cs", 15, 18); |
| 22 | var hits = IntercomMessageCodeCorrespondenceProjector.Find(entries, query, workspaceRoot: null); |
| 23 | |
| 24 | Assert.Single(hits); |
| 25 | Assert.Equal(1, hits[0].Ordinal); |
| 26 | } |
| 27 | |
| 28 | [Fact] |
| 29 | public void Find_NonOverlapping_ReturnsEmpty() |
| 30 | { |
| 31 | var lane = new[] { laneMessage(1, 0, attach("src/Foo.cs", 10, 20)) }; |
| 32 | var entries = IntercomMessageCodeCorrespondenceProjector.BuildInferred(lane); |
| 33 | var query = new IntercomCodeRefQuery("src/Foo.cs", 50, 60); |
| 34 | var hits = IntercomMessageCodeCorrespondenceProjector.Find(entries, query, null); |
| 35 | |
| 36 | Assert.Empty(hits); |
| 37 | } |
| 38 | |
| 39 | [Fact] |
| 40 | public void Find_FileOnlyQuery_MatchesAnchorWithoutLines() |
| 41 | { |
| 42 | var lane = new[] { laneMessage(1, 0, new AttachmentAnchor { File = "src/Bar.cs" }) }; |
| 43 | var entries = IntercomMessageCodeCorrespondenceProjector.BuildInferred(lane); |
| 44 | var query = new IntercomCodeRefQuery("src/Bar.cs", null, null); |
| 45 | var hits = IntercomMessageCodeCorrespondenceProjector.Find(entries, query, null); |
| 46 | |
| 47 | Assert.Single(hits); |
| 48 | } |
| 49 | |
| 50 | [Fact] |
| 51 | public void Find_SameFileDifferentMemberKeys_MatchesByMemberOnly() |
| 52 | { |
| 53 | var lane = new[] |
| 54 | { |
| 55 | laneMessage(1, 0, attach("src/Foo.cs", 10, 20, "M:Foo.Bar")), |
| 56 | laneMessage(2, 1, attach("src/Foo.cs", 10, 20, "M:Foo.Baz")), |
| 57 | }; |
| 58 | |
| 59 | var entries = IntercomMessageCodeCorrespondenceProjector.BuildInferred(lane); |
| 60 | var query = IntercomCodeRefQuery.FromAnchor(new AttachmentAnchor |
| 61 | { |
| 62 | File = "src/Foo.cs", |
| 63 | LineStart = 99, |
| 64 | LineEnd = 99, |
| 65 | MemberKey = "M:Foo.Bar", |
| 66 | }); |
| 67 | var hits = IntercomMessageCodeCorrespondenceProjector.Find(entries, query, null); |
| 68 | |
| 69 | Assert.Single(hits); |
| 70 | Assert.Equal(1, hits[0].Ordinal); |
| 71 | } |
| 72 | |
| 73 | [Fact] |
| 74 | public void TryParse_LineLiteral_RequiresActiveFile() |
| 75 | { |
| 76 | var editor = new IntercomAttachmentResolveAtSend.EditorSnapshot(null, "", null, null, null); |
| 77 | Assert.False(IntercomCodeRefParser.TryParse("L:10-20", editor, null, null, out _, out var err)); |
| 78 | Assert.Contains("активного файла", err, StringComparison.Ordinal); |
| 79 | } |
| 80 | |
| 81 | private static IntercomMessageCodeCorrespondenceProjector.LaneMessage laneMessage( |
| 82 | int ordinal, |
| 83 | int messageIndex, |
| 84 | params AttachmentAnchor[] attachments) => |
| 85 | new(ordinal, messageIndex, Guid.NewGuid(), attachments); |
| 86 | |
| 87 | private static AttachmentAnchor attach(string file, int start, int end, string? memberKey = null) => |
| 88 | new() |
| 89 | { |
| 90 | File = file, |
| 91 | LineStart = start, |
| 92 | LineEnd = end, |
| 93 | MemberKey = memberKey, |
| 94 | AttachmentShape = memberKey is not null ? "member" : "text-range", |
| 95 | }; |
| 96 | } |
| 97 | |