Skip to content

Commit c5db597

Browse files
committed
Add tests for SARIF diff
1 parent 73b6cc4 commit c5db597

File tree

2 files changed

+196
-5
lines changed

2 files changed

+196
-5
lines changed

extensions/ql-vscode/src/compare/sarif-diff.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,28 @@ function toCanonicalResult(result: Result): Result {
77

88
if (canonicalResult.locations) {
99
canonicalResult.locations = canonicalResult.locations.map((location) => {
10-
const canonicalLocation = {
11-
...location,
12-
};
10+
if (location.physicalLocation?.artifactLocation?.index !== undefined) {
11+
const canonicalLocation = {
12+
...location,
13+
};
14+
15+
canonicalLocation.physicalLocation = {
16+
...canonicalLocation.physicalLocation,
17+
};
1318

14-
if (canonicalLocation.physicalLocation?.artifactLocation) {
1519
canonicalLocation.physicalLocation.artifactLocation = {
1620
...canonicalLocation.physicalLocation.artifactLocation,
1721
};
22+
1823
// The index is dependent on the result of the SARIF file and usually doesn't really tell
1924
// us anything useful, so we remove it from the comparison.
2025
delete canonicalLocation.physicalLocation.artifactLocation.index;
26+
27+
return canonicalLocation;
2128
}
2229

23-
return canonicalLocation;
30+
// Don't create a new object if we don't need to
31+
return location;
2432
});
2533
}
2634

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import type { Result } from "sarif";
2+
import { sarifDiff } from "../../../src/compare/sarif-diff";
3+
4+
describe("sarifDiff", () => {
5+
const result1: Result = {
6+
message: {
7+
text: "result1",
8+
},
9+
};
10+
const result2: Result = {
11+
message: {
12+
text: "result2",
13+
},
14+
};
15+
const result3: Result = {
16+
message: {
17+
text: "result3",
18+
},
19+
};
20+
21+
it("throws an error when the source query has no results", () => {
22+
expect(() => sarifDiff([], [result1, result2])).toThrow(
23+
"CodeQL Compare: Source query has no results.",
24+
);
25+
});
26+
27+
it("throws an error when the target query has no results", () => {
28+
expect(() => sarifDiff([result1, result2], [])).toThrow(
29+
"CodeQL Compare: Target query has no results.",
30+
);
31+
});
32+
33+
it("throws an error when there is no overlap between the source and target queries", () => {
34+
expect(() => sarifDiff([result1], [result2])).toThrow(
35+
"CodeQL Compare: No overlap between the selected queries.",
36+
);
37+
});
38+
39+
it("return an empty comparison when the results are the same", () => {
40+
expect(sarifDiff([result1, result2], [result1, result2])).toEqual({
41+
from: [],
42+
to: [],
43+
});
44+
});
45+
46+
it("returns the added and removed results", () => {
47+
expect(sarifDiff([result1, result3], [result1, result2])).toEqual({
48+
from: [result3],
49+
to: [result2],
50+
});
51+
});
52+
53+
it("does not use reference equality to compare results", () => {
54+
const result = {
55+
message: {
56+
text: "result1",
57+
},
58+
};
59+
expect(sarifDiff([result], [result1])).toEqual({
60+
from: [],
61+
to: [],
62+
});
63+
});
64+
65+
it("does not take into account the index of the artifact location", () => {
66+
const result1: Result = {
67+
message: {
68+
text: "result1",
69+
},
70+
locations: [
71+
{
72+
physicalLocation: {
73+
artifactLocation: {
74+
uri: "file:///path/to/file1",
75+
uriBaseId: "%SRCROOT%",
76+
index: 1,
77+
},
78+
},
79+
},
80+
],
81+
};
82+
const result2: Result = {
83+
message: {
84+
text: "result1",
85+
},
86+
locations: [
87+
{
88+
physicalLocation: {
89+
artifactLocation: {
90+
uri: "file:///path/to/file1",
91+
uriBaseId: "%SRCROOT%",
92+
index: 2,
93+
},
94+
},
95+
},
96+
],
97+
};
98+
expect(sarifDiff([result1], [result2])).toEqual({
99+
from: [],
100+
to: [],
101+
});
102+
});
103+
104+
it("takes into account the other properties of the artifact location", () => {
105+
const result1: Result = {
106+
message: {
107+
text: "result1",
108+
},
109+
locations: [
110+
{
111+
physicalLocation: {
112+
artifactLocation: {
113+
uri: "file:///path/to/file1",
114+
uriBaseId: "%SRCROOT%",
115+
},
116+
},
117+
},
118+
],
119+
};
120+
const result2: Result = {
121+
message: {
122+
text: "result1",
123+
},
124+
locations: [
125+
{
126+
physicalLocation: {
127+
artifactLocation: {
128+
uri: "file:///path/to/file2",
129+
uriBaseId: "%SRCROOT%",
130+
},
131+
},
132+
},
133+
],
134+
};
135+
expect(sarifDiff([result1], [result1, result2])).toEqual({
136+
from: [],
137+
to: [result2],
138+
});
139+
});
140+
141+
it("does not modify the input", () => {
142+
const result1: Result = {
143+
message: {
144+
text: "result1",
145+
},
146+
locations: [
147+
{
148+
physicalLocation: {
149+
artifactLocation: {
150+
uri: "file:///path/to/file1",
151+
uriBaseId: "%SRCROOT%",
152+
index: 1,
153+
},
154+
},
155+
},
156+
],
157+
};
158+
const result1Copy = JSON.parse(JSON.stringify(result1));
159+
const result2: Result = {
160+
message: {
161+
text: "result1",
162+
},
163+
locations: [
164+
{
165+
physicalLocation: {
166+
artifactLocation: {
167+
uri: "file:///path/to/file1",
168+
uriBaseId: "%SRCROOT%",
169+
index: 2,
170+
},
171+
},
172+
},
173+
],
174+
};
175+
const result2Copy = JSON.parse(JSON.stringify(result2));
176+
expect(sarifDiff([result1], [result2])).toEqual({
177+
from: [],
178+
to: [],
179+
});
180+
expect(result1).toEqual(result1Copy);
181+
expect(result2).toEqual(result2Copy);
182+
});
183+
});

0 commit comments

Comments
 (0)