track-cli 4.0.3 → 4.1.0-rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/_dnt.shims.d.ts +1 -1
- package/esm/_dnt.test_shims.d.ts +20 -0
- package/esm/_dnt.test_shims.js +77 -0
- package/esm/deps/deno.land/std@0.195.0/_util/diff.d.ts +26 -0
- package/esm/deps/deno.land/std@0.195.0/_util/diff.js +311 -0
- package/esm/deps/deno.land/std@0.195.0/assert/_constants.d.ts +1 -0
- package/esm/deps/deno.land/std@0.195.0/assert/_constants.js +2 -0
- package/esm/deps/deno.land/std@0.195.0/assert/_format.d.ts +1 -0
- package/esm/deps/deno.land/std@0.195.0/assert/_format.js +23 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_almost_equals.d.ts +18 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_almost_equals.js +32 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_array_includes.d.ts +14 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_array_includes.js +38 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_equals.d.ts +17 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_equals.js +45 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_exists.d.ts +5 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_exists.js +14 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_false.d.ts +4 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_false.js +7 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_instance_of.d.ts +8 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_instance_of.js +38 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_is_error.d.ts +7 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_is_error.js +26 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_match.d.ts +5 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_match.js +13 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_equals.d.ts +14 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_equals.js +37 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_instance_of.d.ts +5 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_instance_of.js +14 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_match.d.ts +5 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_match.js +14 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_strict_equals.d.ts +11 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_not_strict_equals.js +20 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_object_match.d.ts +5 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_object_match.js +78 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_rejects.d.ts +64 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_rejects.js +50 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_strict_equals.d.ts +23 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_strict_equals.js +60 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_string_includes.d.ts +5 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_string_includes.js +13 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_throws.d.ts +54 -0
- package/esm/deps/deno.land/std@0.195.0/assert/assert_throws.js +44 -0
- package/esm/deps/deno.land/std@0.195.0/assert/equal.d.ts +6 -0
- package/esm/deps/deno.land/std@0.195.0/assert/equal.js +102 -0
- package/esm/deps/deno.land/std@0.195.0/assert/fail.d.ts +4 -0
- package/esm/deps/deno.land/std@0.195.0/assert/fail.js +9 -0
- package/esm/deps/deno.land/std@0.195.0/assert/mod.d.ts +32 -0
- package/esm/deps/deno.land/std@0.195.0/assert/mod.js +33 -0
- package/esm/deps/deno.land/std@0.195.0/assert/unimplemented.d.ts +2 -0
- package/esm/deps/deno.land/std@0.195.0/assert/unimplemented.js +7 -0
- package/esm/deps/deno.land/std@0.195.0/assert/unreachable.d.ts +2 -0
- package/esm/deps/deno.land/std@0.195.0/assert/unreachable.js +6 -0
- package/esm/deps/deno.land/std@0.195.0/testing/_test_suite.d.ts +70 -0
- package/esm/deps/deno.land/std@0.195.0/testing/_test_suite.js +321 -0
- package/esm/deps/deno.land/std@0.195.0/testing/asserts.d.ts +329 -0
- package/esm/deps/deno.land/std@0.195.0/testing/asserts.js +330 -0
- package/esm/deps/deno.land/std@0.195.0/testing/bdd.d.ts +440 -0
- package/esm/deps/deno.land/std@0.195.0/testing/bdd.js +215 -0
- package/esm/deps/deno.land/std@0.195.0/testing/mock.d.ts +110 -0
- package/esm/deps/deno.land/std@0.195.0/testing/mock.js +746 -0
- package/esm/src/action/clone.js +4 -3
- package/esm/src/action/frontend-template-switch.d.ts +1 -0
- package/esm/src/action/frontend-template-switch.js +53 -0
- package/esm/src/action/frontend-template.d.ts +2 -0
- package/esm/src/action/frontend-template.js +12 -0
- package/esm/src/action/lang.js +11 -2
- package/esm/src/action/run.js +6 -7
- package/esm/src/main.js +9 -2
- package/esm/src/meta.d.ts +1 -1
- package/esm/src/meta.js +108 -25
- package/esm/src/orca/client.js +1 -1
- package/esm/src/shared/config.d.ts +1 -0
- package/esm/src/shared/errors.d.ts +7 -1
- package/esm/src/shared/errors.js +16 -3
- package/esm/src/shared/file.js +1 -1
- package/esm/src/shared/mod.d.ts +1 -1
- package/esm/src/shared/mod.js +10 -2
- package/esm/src/shared/types.d.ts +16 -0
- package/esm/src/shared/types.js +2 -0
- package/esm/src/track/client.d.ts +4 -1
- package/esm/src/track/test.d.ts +6 -2
- package/esm/src/track/test.js +28 -5
- package/esm/src/track/training.d.ts +4 -1
- package/esm/src/track/training.js +9 -0
- package/esm/test/shared/config_test.d.ts +1 -0
- package/esm/test/shared/config_test.js +57 -0
- package/esm/test/shared/file_test.d.ts +1 -0
- package/esm/test/shared/file_test.js +265 -0
- package/esm/test/shared/mod_test.d.ts +1 -0
- package/esm/test/shared/mod_test.js +353 -0
- package/package.json +1 -1
- package/test_runner.js +186 -0
package/esm/src/track/test.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ExamCanceled, ExamExpired, ExamSubmitted, ExamUnread, InvalidChallengeId, OtherError, } from "../shared/errors.js";
|
|
1
|
+
import { ExamCanceled, ExamExpired, ExamSubmitted, ExamUnread, InvalidChallengeId, OtherError, UnsupportedChallenge, } from "../shared/errors.js";
|
|
2
2
|
import { HttpStatus } from "../shared/mod.js";
|
|
3
3
|
import { ChallengeStyle, } from "../shared/types.js";
|
|
4
4
|
import { FormType, TrackClientBase, } from "./client.js";
|
|
5
5
|
// @ts-ignore: has no exported member
|
|
6
6
|
import { CookieJar, fetch } from "node-fetch-cookies";
|
|
7
7
|
export class TestClient extends TrackClientBase {
|
|
8
|
-
constructor(baseUrl, orgName, token, challengeId, basic, cookies) {
|
|
8
|
+
constructor(baseUrl, orgName, token, challengeId, basic, cookies, applicantExamId, challengeResultId) {
|
|
9
9
|
super(baseUrl, basic, cookies);
|
|
10
10
|
Object.defineProperty(this, "orgName", {
|
|
11
11
|
enumerable: true,
|
|
@@ -40,6 +40,8 @@ export class TestClient extends TrackClientBase {
|
|
|
40
40
|
this.orgName = orgName;
|
|
41
41
|
this.token = token;
|
|
42
42
|
this.challengeId = challengeId;
|
|
43
|
+
this.applicantExamId = applicantExamId ?? 0;
|
|
44
|
+
this.resultId = challengeResultId ?? 0;
|
|
43
45
|
}
|
|
44
46
|
config() {
|
|
45
47
|
return {
|
|
@@ -69,6 +71,9 @@ export class TestClient extends TrackClientBase {
|
|
|
69
71
|
if (!challenge) {
|
|
70
72
|
throw new InvalidChallengeId(this.challengeId);
|
|
71
73
|
}
|
|
74
|
+
else if (!this.isChallengeSupported(challenge)) {
|
|
75
|
+
throw new UnsupportedChallenge(this.challengeId);
|
|
76
|
+
}
|
|
72
77
|
this.applicantExamId = applicantExam.id;
|
|
73
78
|
this.resultId = result?.id || 0;
|
|
74
79
|
return challenge;
|
|
@@ -98,14 +103,24 @@ export class TestClient extends TrackClientBase {
|
|
|
98
103
|
return examSession.challengesSets
|
|
99
104
|
.flatMap((s) => s.challenges)
|
|
100
105
|
.map((esc) => toChallengeSession(esc, result))
|
|
101
|
-
.find((c) => c.challengeId === this.challengeId
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
.find((c) => c.challengeId === this.challengeId);
|
|
107
|
+
}
|
|
108
|
+
isChallengeSupported(c) {
|
|
109
|
+
return (c.style === ChallengeStyle.Development ||
|
|
110
|
+
c.style === ChallengeStyle.Algorithm ||
|
|
111
|
+
c.style === ChallengeStyle.Function ||
|
|
112
|
+
c.style === ChallengeStyle.Frontend);
|
|
104
113
|
}
|
|
105
114
|
async languages() {
|
|
106
115
|
return (await this._get(`/api/enum/challenges/programminglanguages`))
|
|
107
116
|
.map(toProgrammingLanguageInfo);
|
|
108
117
|
}
|
|
118
|
+
async frontendTemplates() {
|
|
119
|
+
return await this._get(`/api/dock-public/v2/consumer/frontend-templates`);
|
|
120
|
+
}
|
|
121
|
+
async frontendTemplate(code) {
|
|
122
|
+
return await this._get(`/api/dock-public/v2/consumer/frontend-templates/${code}`);
|
|
123
|
+
}
|
|
109
124
|
async start() {
|
|
110
125
|
return await this._put(`/api/applicants/exams/${this.applicantExamId}/results/${this.resultId}/start`, FormType.URLEncoded, {
|
|
111
126
|
takenBy: 3, // 3 = LocalMachine
|
|
@@ -121,6 +136,12 @@ export class TestClient extends TrackClientBase {
|
|
|
121
136
|
programmingLanguage: language,
|
|
122
137
|
}); // ChallengeResult
|
|
123
138
|
}
|
|
139
|
+
async updateFrontendTemplate(seriesCode) {
|
|
140
|
+
return await this._post(`/api/applicants/exams/${this.applicantExamId}/results/${this.resultId}/frontend/switch-frontend-template`, FormType.JSON, {
|
|
141
|
+
seriesCode,
|
|
142
|
+
forceReset: true,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
124
145
|
async timeLeft() {
|
|
125
146
|
return await this._get(`/api/applicants/exams/${this.applicantExamId}/results/${this.resultId}/timeleft`);
|
|
126
147
|
}
|
|
@@ -171,6 +192,8 @@ function toChallengeSession(esc, result) {
|
|
|
171
192
|
timeLimitMinutes: esc.timeLimitMinutes,
|
|
172
193
|
displayOrder: esc.displayOrder,
|
|
173
194
|
programmingLanguages: esc.programmingLanguages,
|
|
195
|
+
allowedTemplateSeriesCodes: esc.frontendStyleConfig
|
|
196
|
+
?.allowedTemplateSeriesCodes,
|
|
174
197
|
localCodingAllowed: esc.localExamEnabled,
|
|
175
198
|
openTestcases: esc.openTestcases,
|
|
176
199
|
result,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TrackTrainingConfigPart } from "../shared/config.js";
|
|
2
|
-
import { ChallengeResult, ChallengeSession, CodingContext, ProgrammingLanguage, ProgrammingLanguageInfo, SaveFilesRequest } from "../shared/types.js";
|
|
2
|
+
import { ChallengeResult, ChallengeSession, CodingContext, FrontendTemplateInfo, ProgrammingLanguage, ProgrammingLanguageInfo, SaveFilesRequest } from "../shared/types.js";
|
|
3
3
|
import { BasicAuth, TrackClient, TrackClientBase } from "./client.js";
|
|
4
4
|
export declare class TrainingClient extends TrackClientBase implements TrackClient {
|
|
5
5
|
private orgName;
|
|
@@ -13,9 +13,12 @@ export declare class TrainingClient extends TrackClientBase implements TrackClie
|
|
|
13
13
|
startChallengeSession(): Promise<ChallengeSession>;
|
|
14
14
|
continueChallengeSession(): Promise<ChallengeSession>;
|
|
15
15
|
languages(): Promise<ProgrammingLanguageInfo[]>;
|
|
16
|
+
frontendTemplates(): Promise<FrontendTemplateInfo[]>;
|
|
17
|
+
frontendTemplate(_code: string): Promise<FrontendTemplateInfo>;
|
|
16
18
|
start(): Promise<ChallengeResult>;
|
|
17
19
|
prepare(): Promise<ChallengeResult>;
|
|
18
20
|
updateLanguage(language: ProgrammingLanguage): Promise<void>;
|
|
21
|
+
updateFrontendTemplate(_templateCode: string): Promise<void>;
|
|
19
22
|
timeLeft(): Promise<number>;
|
|
20
23
|
context(): Promise<CodingContext>;
|
|
21
24
|
presigned(files: string[]): Promise<{
|
|
@@ -74,6 +74,12 @@ export class TrainingClient extends TrackClientBase {
|
|
|
74
74
|
return (await this._get(`/cli/languages`))
|
|
75
75
|
.map(toProgrammingLanguageInfo);
|
|
76
76
|
}
|
|
77
|
+
frontendTemplates() {
|
|
78
|
+
throw new OtherError("Frontend templates are not supported in training mode");
|
|
79
|
+
}
|
|
80
|
+
frontendTemplate(_code) {
|
|
81
|
+
throw new OtherError("Frontend templates are not supported in training mode");
|
|
82
|
+
}
|
|
77
83
|
async start() {
|
|
78
84
|
return await this._put(`/api/train/${this.klassId}/challenges/results/${this.klassResultId}/start`, FormType.JSON, {
|
|
79
85
|
takenBy: 3, // 3 = LocalMachine
|
|
@@ -87,6 +93,9 @@ export class TrainingClient extends TrackClientBase {
|
|
|
87
93
|
lang: language,
|
|
88
94
|
});
|
|
89
95
|
}
|
|
96
|
+
updateFrontendTemplate(_templateCode) {
|
|
97
|
+
throw new OtherError("Frontend templates are not supported in training mode");
|
|
98
|
+
}
|
|
90
99
|
async timeLeft() {
|
|
91
100
|
return await this._get(`/api/train/${this.klassId}/challenges/results/${this.klassResultId}/timeleft`);
|
|
92
101
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.test_shims.js";
|
|
2
|
+
import * as config from "../../src/shared/config.js";
|
|
3
|
+
import { MissingConfigFile } from "../../src/shared/errors.js";
|
|
4
|
+
import { assertEquals, assertRejects } from "../../deps/deno.land/std@0.195.0/testing/asserts.js";
|
|
5
|
+
import { afterEach, beforeEach, describe, it } from "../../deps/deno.land/std@0.195.0/testing/bdd.js";
|
|
6
|
+
import { TrackApp } from "../../src/shared/types.js";
|
|
7
|
+
const testConfig = {
|
|
8
|
+
app: TrackApp.Test,
|
|
9
|
+
baseUrl: "https://app.tracks.run",
|
|
10
|
+
orgName: "anorg",
|
|
11
|
+
basicAuth: {
|
|
12
|
+
username: "user",
|
|
13
|
+
password: "pass",
|
|
14
|
+
},
|
|
15
|
+
token: "SECRET_TOKEN",
|
|
16
|
+
applicantExamId: 100,
|
|
17
|
+
challengeId: 200,
|
|
18
|
+
challengeResultId: 300,
|
|
19
|
+
cookies: {
|
|
20
|
+
PLAY_SESSION: "session",
|
|
21
|
+
},
|
|
22
|
+
programmingLanguage: 10,
|
|
23
|
+
};
|
|
24
|
+
describe("save()", () => {
|
|
25
|
+
let dir;
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
dir = await dntShim.Deno.makeTempDir();
|
|
28
|
+
});
|
|
29
|
+
afterEach(async () => {
|
|
30
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
31
|
+
});
|
|
32
|
+
it("should save config to file with json format", async () => {
|
|
33
|
+
const path = `${dir}/config.json`;
|
|
34
|
+
await config.save(testConfig, { path });
|
|
35
|
+
const actual = new TextDecoder().decode(await dntShim.Deno.readFile(path));
|
|
36
|
+
assertEquals(JSON.parse(actual), testConfig);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("load()", () => {
|
|
40
|
+
let dir;
|
|
41
|
+
beforeEach(async () => {
|
|
42
|
+
dir = await dntShim.Deno.makeTempDir();
|
|
43
|
+
});
|
|
44
|
+
afterEach(async () => {
|
|
45
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
46
|
+
});
|
|
47
|
+
it("should save config to file with json format", async () => {
|
|
48
|
+
const path = `${dir}/config.json`;
|
|
49
|
+
await dntShim.Deno.writeFile(path, new TextEncoder().encode(JSON.stringify(testConfig)));
|
|
50
|
+
const actual = await config.load({ path });
|
|
51
|
+
assertEquals(actual, testConfig);
|
|
52
|
+
});
|
|
53
|
+
it("should throw error if config file does not exist", async () => {
|
|
54
|
+
const path = `${dir}/config.json`;
|
|
55
|
+
await assertRejects(async () => await config.load({ path }), MissingConfigFile);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.test_shims.js";
|
|
2
|
+
import * as file from "../../src/shared/file.js";
|
|
3
|
+
import { assertEquals, assertObjectMatch } from "../../deps/deno.land/std@0.195.0/testing/asserts.js";
|
|
4
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, it, } from "../../deps/deno.land/std@0.195.0/testing/bdd.js";
|
|
5
|
+
async function prepareFiles(dir, files) {
|
|
6
|
+
for (const [name, content] of Object.entries(files)) {
|
|
7
|
+
if (typeof content === "string") {
|
|
8
|
+
await dntShim.Deno.writeTextFile(`${dir}/${name}`, content);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
await dntShim.Deno.mkdir(`${dir}/${name}`);
|
|
12
|
+
await prepareFiles(`${dir}/${name}`, content);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
describe("pathsToFilenameSet()", () => {
|
|
17
|
+
let dir;
|
|
18
|
+
const files = {
|
|
19
|
+
"a.txt": "hello",
|
|
20
|
+
"b": {
|
|
21
|
+
"c.txt": "world",
|
|
22
|
+
"d": {
|
|
23
|
+
"e.txt": "foo",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
beforeAll(async () => {
|
|
28
|
+
dir = await dntShim.Deno.makeTempDir();
|
|
29
|
+
await prepareFiles(dir, files);
|
|
30
|
+
});
|
|
31
|
+
afterAll(async () => {
|
|
32
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
33
|
+
});
|
|
34
|
+
it("should list only existing files without options", async () => {
|
|
35
|
+
const result = await file.pathsToFilenameSet(["a.txt", "b/c.txt", "b/d", "x/y", "z.txt"], { root: dir });
|
|
36
|
+
assertEquals(result, new Set(["a.txt", "b/c.txt"]));
|
|
37
|
+
});
|
|
38
|
+
it("should search files recursively with recursive = true", async () => {
|
|
39
|
+
const result = await file.pathsToFilenameSet(["a.txt", "b", "x/y", "z.txt"], { recursive: true, root: dir });
|
|
40
|
+
assertEquals(result, new Set(["a.txt", "b/c.txt", "b/d/e.txt"]));
|
|
41
|
+
});
|
|
42
|
+
it("should search files recursively and list non-existing files and directories with recursive = true and allowNonExistent = true", async () => {
|
|
43
|
+
const result = await file.pathsToFilenameSet(["a.txt", "b", "x/y", "z.txt"], { recursive: true, allowNonExistent: true, root: dir });
|
|
44
|
+
assertEquals(result, new Set(["a.txt", "b/c.txt", "b/d/e.txt", "x/y", "z.txt"]));
|
|
45
|
+
});
|
|
46
|
+
it("should support absolute paths", async () => {
|
|
47
|
+
const result = await file.pathsToFilenameSet([`${dir}/a.txt`, `${dir}/b`, `${dir}/x/y`, `${dir}/z.txt`], { recursive: true, allowNonExistent: true, root: dir });
|
|
48
|
+
assertEquals(result, new Set(["a.txt", "b/c.txt", "b/d/e.txt", "x/y", "z.txt"]));
|
|
49
|
+
});
|
|
50
|
+
it("should support only paths with root", async () => {
|
|
51
|
+
const anotherDir = await dntShim.Deno.makeTempDir();
|
|
52
|
+
await prepareFiles(anotherDir, files);
|
|
53
|
+
const result = await file.pathsToFilenameSet([`${dir}/a.txt`, `${anotherDir}/z.txt`], { recursive: true, allowNonExistent: true, root: dir });
|
|
54
|
+
assertEquals(result, new Set(["a.txt"]));
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe("stat()", () => {
|
|
58
|
+
let dir;
|
|
59
|
+
const files = {
|
|
60
|
+
"a.txt": "hello",
|
|
61
|
+
"b": {
|
|
62
|
+
"c.txt": "world",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
beforeAll(async () => {
|
|
66
|
+
dir = await dntShim.Deno.makeTempDir();
|
|
67
|
+
await prepareFiles(dir, files);
|
|
68
|
+
});
|
|
69
|
+
afterAll(async () => {
|
|
70
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
71
|
+
});
|
|
72
|
+
it("should return stat of file", async () => {
|
|
73
|
+
const result = await file.stat(`${dir}/a.txt`);
|
|
74
|
+
assertObjectMatch(result, {
|
|
75
|
+
isFile: true,
|
|
76
|
+
isDirectory: false,
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
it("should return stat of directory", async () => {
|
|
80
|
+
const result = await file.stat(`${dir}/b`);
|
|
81
|
+
assertObjectMatch(result, {
|
|
82
|
+
isFile: false,
|
|
83
|
+
isDirectory: true,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
it("should return null if file does not exist", async () => {
|
|
87
|
+
const result = await file.stat(`${dir}/x.txt`);
|
|
88
|
+
assertEquals(result, null);
|
|
89
|
+
});
|
|
90
|
+
it("should support subdirectories", async () => {
|
|
91
|
+
const result = await file.stat(`${dir}/b/c.txt`);
|
|
92
|
+
assertObjectMatch(result, {
|
|
93
|
+
isFile: true,
|
|
94
|
+
isDirectory: false,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("isEmptyDirectory()", () => {
|
|
99
|
+
let dir;
|
|
100
|
+
const files = {
|
|
101
|
+
"a.txt": "hello",
|
|
102
|
+
"b": {
|
|
103
|
+
"c.txt": "world",
|
|
104
|
+
},
|
|
105
|
+
"d": {},
|
|
106
|
+
};
|
|
107
|
+
beforeAll(async () => {
|
|
108
|
+
dir = await dntShim.Deno.makeTempDir();
|
|
109
|
+
await prepareFiles(dir, files);
|
|
110
|
+
});
|
|
111
|
+
afterAll(async () => {
|
|
112
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
113
|
+
});
|
|
114
|
+
it("should return ture if directory is empty", async () => {
|
|
115
|
+
const result = await file.isEmptyDirectory(`${dir}/d`);
|
|
116
|
+
assertEquals(result, true);
|
|
117
|
+
});
|
|
118
|
+
it("should return false if directory is not empty", async () => {
|
|
119
|
+
const result = await file.isEmptyDirectory(`${dir}/b`);
|
|
120
|
+
assertEquals(result, false);
|
|
121
|
+
});
|
|
122
|
+
it("should return false if directory nor file does not exist", async () => {
|
|
123
|
+
const result = await file.isEmptyDirectory(`${dir}/x`);
|
|
124
|
+
assertEquals(result, false);
|
|
125
|
+
});
|
|
126
|
+
it("should return false if path is a file", async () => {
|
|
127
|
+
const result = await file.isEmptyDirectory(`${dir}/a.txt`);
|
|
128
|
+
assertEquals(result, false);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe("getAllDirFiles()", () => {
|
|
132
|
+
let dir;
|
|
133
|
+
const files = {
|
|
134
|
+
"a.txt": "hello",
|
|
135
|
+
"b": {
|
|
136
|
+
"c.txt": "world",
|
|
137
|
+
},
|
|
138
|
+
"d": {},
|
|
139
|
+
};
|
|
140
|
+
beforeAll(async () => {
|
|
141
|
+
dir = await dntShim.Deno.makeTempDir();
|
|
142
|
+
await prepareFiles(dir, files);
|
|
143
|
+
});
|
|
144
|
+
afterAll(async () => {
|
|
145
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe("untgz()", () => {
|
|
149
|
+
it("should extract tar.gz file", async () => {
|
|
150
|
+
const input = `
|
|
151
|
+
1f8b 0800 0000 0000 0003 edd5 df0a 8230
|
|
152
|
+
1c86 e11d 7715 5e81 6eee dff5 440a 4586
|
|
153
|
+
6046 75f7 b9a1 d091 d4c1 26d1 fb30 1c8c.
|
|
154
|
+
813f f8e0 5b59 89e4 e4c4 4b19 76e5 edbc
|
|
155
|
+
1b1f cf67 4219 e38c 9261 09a9 c23d 51d8
|
|
156
|
+
f4a3 0971 bb8e fba1 28c4 e5f4 dcaf dd6b
|
|
157
|
+
fac3 b91d 724c 9455 591d dbae ebcb f131
|
|
158
|
+
26fb 4708 d819 b392 bf5b f2d7 deaa 29ff
|
|
159
|
+
5a5a 270a 996c a237 7f9e 7f4c 7fb7 f514
|
|
160
|
+
d84a 59dd fba1 6b92 be02 b1ff adfd a4ff
|
|
161
|
+
b5f7 d3b9 52da d2ff 592c f9c7 6fa2 57e0
|
|
162
|
+
abfe 8ff9 ebda 28fa 3f87 983b fd0f 0000
|
|
163
|
+
0000 0000 0000 0000 3fef 0500 d28d ca00
|
|
164
|
+
2800 00
|
|
165
|
+
`
|
|
166
|
+
.replaceAll(" ", "")
|
|
167
|
+
.match(/.{2}/g)
|
|
168
|
+
?.map((byte) => parseInt(byte, 16));
|
|
169
|
+
const expected = [
|
|
170
|
+
{ name: "hello.txt", content: "hello\n" },
|
|
171
|
+
{ name: "world/world.txt", content: "world\n" },
|
|
172
|
+
];
|
|
173
|
+
const dir = await dntShim.Deno.makeTempDir();
|
|
174
|
+
await file.untgz(new Uint8Array(input), dir);
|
|
175
|
+
for (const { name, content } of expected) {
|
|
176
|
+
const actual = await dntShim.Deno.readTextFile(`${dir}/${name}`);
|
|
177
|
+
assertEquals(actual, content);
|
|
178
|
+
}
|
|
179
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
describe("toNixStyle()", () => {
|
|
183
|
+
describe("on Windows", () => {
|
|
184
|
+
const originalSeparator = file._internals.SEP;
|
|
185
|
+
beforeAll(() => {
|
|
186
|
+
file._internals.SEP = "/";
|
|
187
|
+
});
|
|
188
|
+
afterAll(() => {
|
|
189
|
+
file._internals.SEP = originalSeparator;
|
|
190
|
+
});
|
|
191
|
+
it("should return path with forward slashes", () => {
|
|
192
|
+
assertEquals(file.toNixStyle("a\\b\\c"), "a/b/c");
|
|
193
|
+
assertEquals(file.toNixStyle("a/b/c"), "a/b/c");
|
|
194
|
+
assertEquals(file.toNixStyle("a\\b/c"), "a/b/c");
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe("on Linux and macOS", () => {
|
|
198
|
+
const originalSeparator = file._internals.SEP;
|
|
199
|
+
beforeAll(() => {
|
|
200
|
+
file._internals.SEP = "/";
|
|
201
|
+
});
|
|
202
|
+
afterAll(() => {
|
|
203
|
+
file._internals.SEP = originalSeparator;
|
|
204
|
+
});
|
|
205
|
+
it("should return path with forward slashes", () => {
|
|
206
|
+
assertEquals(file.toNixStyle("a\\b\\c"), "a/b/c");
|
|
207
|
+
assertEquals(file.toNixStyle("a/b/c"), "a/b/c");
|
|
208
|
+
assertEquals(file.toNixStyle("a\\b/c"), "a/b/c");
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe("toNativeStyle()", () => {
|
|
213
|
+
describe("on Windows", () => {
|
|
214
|
+
const originalSeparator = file._internals.SEP;
|
|
215
|
+
beforeAll(() => {
|
|
216
|
+
file._internals.SEP = "\\";
|
|
217
|
+
});
|
|
218
|
+
afterAll(() => {
|
|
219
|
+
file._internals.SEP = originalSeparator;
|
|
220
|
+
});
|
|
221
|
+
it("should return path with forward slashes", () => {
|
|
222
|
+
assertEquals(file.toNativeStyle("a\\b\\c"), "a\\b\\c");
|
|
223
|
+
assertEquals(file.toNativeStyle("a/b/c"), "a\\b\\c");
|
|
224
|
+
assertEquals(file.toNativeStyle("a\\b/c"), "a\\b\\c");
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
describe("on Linux and macOS", () => {
|
|
228
|
+
const originalSeparator = file._internals.SEP;
|
|
229
|
+
beforeAll(() => {
|
|
230
|
+
file._internals.SEP = "/";
|
|
231
|
+
});
|
|
232
|
+
afterAll(() => {
|
|
233
|
+
file._internals.SEP = originalSeparator;
|
|
234
|
+
});
|
|
235
|
+
it("should return path with forward slashes", () => {
|
|
236
|
+
assertEquals(file.toNativeStyle("a\\b\\c"), "a/b/c");
|
|
237
|
+
assertEquals(file.toNativeStyle("a/b/c"), "a/b/c");
|
|
238
|
+
assertEquals(file.toNativeStyle("a\\b/c"), "a/b/c");
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
describe("getUniqueDirName()", () => {
|
|
243
|
+
let dir;
|
|
244
|
+
const files = {
|
|
245
|
+
"foo": {},
|
|
246
|
+
"foo_1": {},
|
|
247
|
+
"foo_2": {},
|
|
248
|
+
"bar": {},
|
|
249
|
+
};
|
|
250
|
+
beforeEach(async () => {
|
|
251
|
+
dir = await dntShim.Deno.makeTempDir();
|
|
252
|
+
await prepareFiles(dir, files);
|
|
253
|
+
});
|
|
254
|
+
afterEach(async () => {
|
|
255
|
+
await dntShim.Deno.remove(dir, { recursive: true });
|
|
256
|
+
});
|
|
257
|
+
it("should return unique name", async () => {
|
|
258
|
+
const actual = await file.getUniqueDirName("bar", { root: dir });
|
|
259
|
+
assertEquals(actual, "bar_1");
|
|
260
|
+
});
|
|
261
|
+
it("should return unique name with counter > 1 if the candidate exists", async () => {
|
|
262
|
+
const actual = await file.getUniqueDirName("foo", { root: dir });
|
|
263
|
+
assertEquals(actual, "foo_3");
|
|
264
|
+
});
|
|
265
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|