Skip to content

Commit 175f722

Browse files
committed
chore: integration test for getGGShield
1 parent 8c58ee0 commit 175f722

File tree

5 files changed

+308
-179
lines changed

5 files changed

+308
-179
lines changed
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import * as path from "path";
2-
import { ExtensionContext, OutputChannel } from "vscode";
32
import * as fs from "fs";
43
import * as tar from "tar";
54
const AdmZip = require("adm-zip");
5+
import { ExtensionContext, OutputChannel } from "vscode";
66

77
/**
88
* Get the absolute path to GGShield binary. If it doesn't exist, it will be installed.
99
* @param platform The platform of the user
1010
* @param arch The architecture of the user
11-
* @param context The extension context
11+
* @param context The extension context
1212
* @param outputChannel The output channel to use
1313
* @returns The absolute path to the GGShield binary
1414
*/
@@ -57,7 +57,7 @@ export function getGGShield(
5757
* Get the latest version of GGShield
5858
* @returns The latest version of GGShield
5959
*/
60-
function getGGShieldLatestVersion(): string {
60+
export function getGGShieldLatestVersion(): string {
6161
const response = require("sync-request")(
6262
"GET",
6363
"https://api.github.com/repos/GitGuardian/ggshield/releases/latest",
@@ -74,7 +74,7 @@ function getGGShieldLatestVersion(): string {
7474
* @param version The version of GGShield
7575
* @returns The folder name of the GGShield binary
7676
*/
77-
function computeGGShieldFolderName(
77+
export function computeGGShieldFolderName(
7878
platform: NodeJS.Platform,
7979
arch: string,
8080
version: string
@@ -117,7 +117,7 @@ function computeGGShieldFolderName(
117117
* @param ggshieldFolder The folder of the GGShield binary
118118
* @param version The version of GGShield
119119
*/
120-
function installGGShield(
120+
export function installGGShield(
121121
platform: NodeJS.Platform,
122122
arch: string,
123123
ggshieldFolder: string,

src/lib/ggshield-configuration-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ExtensionContext, OutputChannel, workspace } from "vscode";
22
import * as os from "os";
33
import { GGShieldConfiguration } from "./ggshield-configuration";
4-
import { getGGShield } from "./ggshield-resolver-utils";
4+
import { getGGShield } from "./get-ggshield-utils";
55

66
/**
77
* Retrieve configuration from settings
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
import * as assert from "assert";
2+
import * as path from "path";
3+
import * as fs from "fs";
4+
import * as os from "os";
5+
import * as tar from "tar";
6+
const AdmZip = require("adm-zip");
7+
import * as getGGShieldUtils from "../../../lib/get-ggshield-utils";
8+
import { ExtensionContext, window, OutputChannel } from "vscode";
9+
10+
suite("getGGShield integration tests", () => {
11+
let tempDir: string;
12+
let mockContext: ExtensionContext;
13+
let outputChannel: OutputChannel = window.createOutputChannel("GitGuardian");
14+
const platform = process.platform;
15+
const arch = process.arch;
16+
const latestVersion = getGGShieldUtils.getGGShieldLatestVersion();
17+
let originalLog: (message?: any, ...optionalParams: any[]) => void;
18+
let output: string;
19+
20+
setup(() => {
21+
// Create temp directory for tests
22+
tempDir = fs.mkdtempSync(__dirname);
23+
mockContext = {
24+
extensionPath: tempDir,
25+
} as ExtensionContext;
26+
output = ""; // Reset captured output before each test
27+
originalLog = console.log; // Store original console.log
28+
29+
console.log = (message: string) => {
30+
output += message;
31+
};
32+
});
33+
34+
teardown(() => {
35+
if (fs.existsSync(tempDir)) {
36+
fs.rmSync(tempDir, { recursive: true });
37+
console.log = originalLog; // Restore original console.log
38+
}
39+
});
40+
41+
test("returns existing binary path when binary exists", () => {
42+
const binaryPath: string = createFakeBinary(
43+
tempDir,
44+
platform,
45+
arch,
46+
latestVersion
47+
);
48+
const result = getGGShieldUtils.getGGShield(
49+
platform,
50+
arch,
51+
mockContext,
52+
outputChannel
53+
);
54+
55+
assert.strictEqual(result, binaryPath);
56+
assert(fs.existsSync(result));
57+
assert(result.includes(latestVersion));
58+
assert(
59+
!output.includes("Updated to GGShield"),
60+
"installGGShield should not be called when binary exists"
61+
);
62+
});
63+
64+
test("installs binary when it doesn't exist", () => {
65+
const expectedBinaryPath: string = getGGShieldUtils.computeGGShieldPath(
66+
platform,
67+
arch,
68+
path.join(tempDir, "ggshield-internal"),
69+
latestVersion
70+
);
71+
assert(!fs.existsSync(expectedBinaryPath));
72+
73+
const result = getGGShieldUtils.getGGShield(
74+
platform,
75+
arch,
76+
mockContext,
77+
outputChannel
78+
);
79+
80+
assert(fs.existsSync(result));
81+
assert.strictEqual(result, expectedBinaryPath);
82+
assert(result.includes(latestVersion));
83+
assert(
84+
!output.includes("Updated to GGShield"),
85+
"installGGShield should be called once when binary doesn't exist"
86+
);
87+
});
88+
89+
test("updates binary when older version exists", () => {
90+
const oldBinaryPath: string = createFakeBinary(
91+
tempDir,
92+
platform,
93+
arch,
94+
"1.0.0"
95+
);
96+
const result = getGGShieldUtils.getGGShield(
97+
platform,
98+
arch,
99+
mockContext,
100+
outputChannel
101+
);
102+
103+
assert(fs.existsSync(result));
104+
assert(result.includes(latestVersion));
105+
assert(!fs.existsSync(oldBinaryPath));
106+
assert(
107+
!output.includes("Updated to GGShield"),
108+
"installGGShield should be called once when updating binary"
109+
);
110+
});
111+
});
112+
113+
function createFakeBinary(
114+
tempDir: string,
115+
platform: NodeJS.Platform,
116+
arch: string,
117+
version: string
118+
): string {
119+
const ggshieldFolder: string = path.join(tempDir, "ggshield-internal");
120+
const binaryName: string = platform === "win32" ? "ggshield.exe" : "ggshield";
121+
const versionFolder: string = path.join(
122+
ggshieldFolder,
123+
`${getGGShieldUtils.computeGGShieldFolderName(platform, arch, version)}`
124+
);
125+
const binaryPath: string = path.join(versionFolder, binaryName);
126+
fs.mkdirSync(versionFolder, { recursive: true });
127+
fs.writeFileSync(binaryPath, "fake binary content");
128+
return binaryPath;
129+
}
130+
131+
suite("ggshield-resolver-utils", () => {
132+
suite("computeGGShieldPath", () => {
133+
const version = "1.0.0";
134+
const ggshieldFolder = "/path/to/ggshield";
135+
136+
test("computes correct path for Windows", () => {
137+
const result = getGGShieldUtils.computeGGShieldPath(
138+
"win32",
139+
"x64",
140+
ggshieldFolder,
141+
version
142+
);
143+
assert.strictEqual(
144+
result,
145+
path.join(
146+
ggshieldFolder,
147+
"ggshield-1.0.0-x86_64-pc-windows-msvc",
148+
"ggshield.exe"
149+
)
150+
);
151+
});
152+
153+
test("computes correct path for Linux", () => {
154+
const result = getGGShieldUtils.computeGGShieldPath(
155+
"linux",
156+
"x64",
157+
ggshieldFolder,
158+
version
159+
);
160+
assert.strictEqual(
161+
result,
162+
path.join(
163+
ggshieldFolder,
164+
"ggshield-1.0.0-x86_64-unknown-linux-gnu",
165+
"ggshield"
166+
)
167+
);
168+
});
169+
170+
test("computes correct path for macOS x64", () => {
171+
const result = getGGShieldUtils.computeGGShieldPath(
172+
"darwin",
173+
"x64",
174+
ggshieldFolder,
175+
version
176+
);
177+
assert.strictEqual(
178+
result,
179+
path.join(
180+
ggshieldFolder,
181+
"ggshield-1.0.0-x86_64-apple-darwin",
182+
"ggshield"
183+
)
184+
);
185+
});
186+
187+
test("computes correct path for macOS arm64", () => {
188+
const result = getGGShieldUtils.computeGGShieldPath(
189+
"darwin",
190+
"arm64",
191+
ggshieldFolder,
192+
version
193+
);
194+
assert.strictEqual(
195+
result,
196+
path.join(
197+
ggshieldFolder,
198+
"ggshield-1.0.0-arm64-apple-darwin",
199+
"ggshield"
200+
)
201+
);
202+
});
203+
204+
test("throws error for unsupported platform", () => {
205+
assert.throws(() => {
206+
getGGShieldUtils.computeGGShieldPath(
207+
"sunos",
208+
"x64",
209+
ggshieldFolder,
210+
version
211+
);
212+
}, /Unsupported platform/);
213+
});
214+
215+
test("throws error for unsupported architecture", () => {
216+
assert.throws(() => {
217+
getGGShieldUtils.computeGGShieldPath(
218+
"darwin",
219+
"mips",
220+
ggshieldFolder,
221+
version
222+
);
223+
}, /Unsupported architecture/);
224+
});
225+
});
226+
227+
suite("extractGGShieldBinary", () => {
228+
const testContent = "hello world";
229+
const testFileName = "test.txt";
230+
let tempDir: string;
231+
let tarGzPath: string;
232+
let zipPath: string;
233+
234+
setup(() => {
235+
// Create temporary directory
236+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ggshield-test-"));
237+
238+
// Create test file
239+
const testFilePath = path.join(tempDir, testFileName);
240+
fs.writeFileSync(testFilePath, testContent);
241+
242+
// Create tar.gz archive
243+
tarGzPath = path.join(tempDir, "archive.tar.gz");
244+
tar.create(
245+
{
246+
gzip: true,
247+
file: tarGzPath,
248+
cwd: tempDir,
249+
sync: true,
250+
},
251+
[testFileName]
252+
);
253+
254+
// Create zip archive
255+
zipPath = path.join(tempDir, "archive.zip");
256+
const zip = new AdmZip();
257+
zip.addFile(testFileName, Buffer.from(testContent));
258+
zip.writeZip(zipPath);
259+
});
260+
261+
teardown(() => {
262+
// Clean up temporary directory and its contents
263+
fs.rmSync(tempDir, { recursive: true, force: true });
264+
});
265+
266+
test("extracts tar.gz files correctly", () => {
267+
const extractDir = path.join(tempDir, "extract-tar");
268+
fs.mkdirSync(extractDir);
269+
270+
getGGShieldUtils.extractGGShieldBinary(tarGzPath, extractDir);
271+
272+
const extractedContent = fs.readFileSync(
273+
path.join(extractDir, testFileName),
274+
"utf8"
275+
);
276+
assert.strictEqual(extractedContent, testContent);
277+
});
278+
279+
test("extracts zip files correctly", () => {
280+
const extractDir = path.join(tempDir, "extract-zip");
281+
fs.mkdirSync(extractDir);
282+
283+
getGGShieldUtils.extractGGShieldBinary(zipPath, extractDir);
284+
285+
const extractedContent = fs.readFileSync(
286+
path.join(extractDir, testFileName),
287+
"utf8"
288+
);
289+
assert.strictEqual(extractedContent, testContent);
290+
});
291+
292+
test("throws error for unsupported file extension", () => {
293+
const rarPath = path.join(tempDir, "archive.rar");
294+
fs.writeFileSync(rarPath, "unsupported file extension");
295+
296+
assert.throws(() => {
297+
getGGShieldUtils.extractGGShieldBinary(rarPath, tempDir);
298+
}, /Unsupported file extension/);
299+
});
300+
});
301+
});

src/test/suite/lib/ggshield-configuration-utils.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as simple from "simple-mock";
22
import assert = require("assert");
33
import { ExtensionContext, workspace, window } from "vscode";
44
import { getConfiguration } from "../../../lib/ggshield-configuration-utils";
5-
import * as ggshieldResolverUtils from "../../../lib/ggshield-resolver-utils";
5+
import * as ggshieldResolverUtils from "../../../lib/get-ggshield-utils";
66

77
suite("getConfiguration", () => {
88
let getConfigurationMock: simple.Stub<Function>;

0 commit comments

Comments
 (0)