main
rb 96 lines 3.25 KB
Raw
1 # frozen_string_literal: true
2
3 require "rails_helper"
4
5 RSpec.describe GithubPatchIndex do
6 # a.rb: new-file lines 1 (context), 2 (added), 3 (context); line 4 removed only.
7 let(:single_hunk_patch) { "@@ -1,3 +1,3 @@\n line one\n+line two\n line three\n-line four" }
8
9 let(:multi_hunk_patch) do
10 "@@ -1,2 +1,3 @@\n a\n+b\n c\n@@ -10,2 +11,3 @@\n x\n+y\n z"
11 end
12
13 def index_for(patch, filename: "a.rb")
14 described_class.new([ { "filename" => filename, "patch" => patch } ])
15 end
16
17 describe "#valid_line?" do
18 it "accepts added and context lines by new-file number" do
19 index = index_for(single_hunk_patch)
20 expect(index.valid_line?("a.rb", 1)).to be true
21 expect(index.valid_line?("a.rb", 2)).to be true
22 expect(index.valid_line?("a.rb", 3)).to be true
23 end
24
25 it "rejects lines outside the hunks" do
26 index = index_for(single_hunk_patch)
27 expect(index.valid_line?("a.rb", 4)).to be false
28 expect(index.valid_line?("a.rb", 100)).to be false
29 end
30
31 it "rejects unknown files" do
32 expect(index_for(single_hunk_patch).valid_line?("other.rb", 1)).to be false
33 end
34
35 it "indexes every hunk of a multi-hunk patch" do
36 index = index_for(multi_hunk_patch)
37 expect(index.valid_line?("a.rb", 2)).to be true # + in hunk 1
38 expect(index.valid_line?("a.rb", 12)).to be true # + in hunk 2
39 expect(index.valid_line?("a.rb", 7)).to be false # between hunks
40 end
41
42 it "treats a file without a patch (binary) as having no commentable lines" do
43 index = described_class.new([ { "filename" => "logo.png", "patch" => nil } ])
44 expect(index.valid_line?("logo.png", 1)).to be false
45 end
46
47 it "handles a deleted file (only removed lines) with no commentable lines" do
48 index = index_for("@@ -1,2 +0,0 @@\n-gone\n-also gone", filename: "dead.rb")
49 expect(index.valid_line?("dead.rb", 1)).to be false
50 end
51 end
52
53 describe "#clamp" do
54 let(:index) { index_for(single_hunk_patch) }
55
56 it "returns a valid line unchanged" do
57 expect(index.clamp("a.rb", 2)).to eq(2)
58 end
59
60 it "snaps a near miss to the nearest commentable line" do
61 expect(index.clamp("a.rb", 5)).to eq(3)
62 end
63
64 it "drops a far miss" do
65 expect(index.clamp("a.rb", 50)).to be_nil
66 end
67
68 it "drops findings on unknown files or non-integer lines" do
69 expect(index.clamp("other.rb", 2)).to be_nil
70 expect(index.clamp("a.rb", nil)).to be_nil
71 end
72 end
73
74 describe ".annotate_patch" do
75 it "prefixes added and context lines with new-file numbers, leaves removed lines bare" do
76 annotated = described_class.annotate_patch(single_hunk_patch)
77 lines = annotated.lines.map(&:chomp)
78
79 expect(lines[0]).to eq("@@ -1,3 +1,3 @@")
80 expect(lines[1]).to match(/\A\s+1 line one\z/)
81 expect(lines[2]).to match(/\A\s+2 \+line two\z/)
82 expect(lines[3]).to match(/\A\s+3 line three\z/)
83 expect(lines[4]).to eq("-line four")
84 end
85
86 it "restarts numbering at each hunk header" do
87 annotated = described_class.annotate_patch(multi_hunk_patch)
88 expect(annotated).to include(" 11 x")
89 expect(annotated).to include(" 12 +y")
90 end
91
92 it "returns an empty string for a missing patch" do
93 expect(described_class.annotate_patch(nil)).to eq("")
94 end
95 end
96 end