@simplysm/core-node 13.0.0-beta.6 → 13.0.0-beta.7

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.
@@ -1,192 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import path from "path";
3
- import {
4
- pathPosix,
5
- pathNorm,
6
- pathIsChildPath,
7
- pathChangeFileDirectory,
8
- pathGetBasenameWithoutExt,
9
- pathFilterByTargets,
10
- type NormPath,
11
- } from "../../src/utils/path";
12
-
13
- describe("path 함수들", () => {
14
- //#region posix
15
-
16
- describe("pathPosix", () => {
17
- it("단일 경로 인자를 POSIX 스타일로 변환", () => {
18
- const result = pathPosix("C:\\Users\\test\\file.txt");
19
- expect(result).toBe("C:/Users/test/file.txt");
20
- });
21
-
22
- it("여러 경로 인자를 조합하여 POSIX 스타일로 변환", () => {
23
- const result = pathPosix("C:\\Users", "test", "file.txt");
24
- expect(result).toBe("C:/Users/test/file.txt");
25
- });
26
-
27
- it("이미 POSIX 스타일인 경로는 그대로 유지", () => {
28
- const result = pathPosix("/usr/local/bin");
29
- expect(result).toBe("/usr/local/bin");
30
- });
31
-
32
- it("혼합된 경로 구분자 처리", () => {
33
- const result = pathPosix("C:/Users\\test/file.txt");
34
- expect(result).toBe("C:/Users/test/file.txt");
35
- });
36
- });
37
-
38
- //#endregion
39
-
40
- //#region norm
41
-
42
- describe("pathNorm", () => {
43
- it("경로를 정규화하고 NormPath 타입으로 반환", () => {
44
- const result: NormPath = pathNorm("./test/../file.txt");
45
- expect(result).toBe(path.resolve("./test/../file.txt"));
46
- });
47
-
48
- it("여러 경로 인자를 조합하여 정규화", () => {
49
- const basePath = path.resolve("/base");
50
- const result = pathNorm(basePath, "sub", "file.txt");
51
- expect(result).toBe(path.resolve(basePath, "sub", "file.txt"));
52
- });
53
-
54
- it("상대 경로를 절대 경로로 변환", () => {
55
- const result = pathNorm("relative/path");
56
- expect(path.isAbsolute(result)).toBe(true);
57
- });
58
- });
59
-
60
- //#endregion
61
-
62
- //#region isChildPath
63
-
64
- describe("pathIsChildPath", () => {
65
- it("자식 경로인 경우 true 반환", () => {
66
- const parent = pathNorm("/parent/dir");
67
- const child = pathNorm("/parent/dir/child/file.txt");
68
- expect(pathIsChildPath(child, parent)).toBe(true);
69
- });
70
-
71
- it("같은 경로인 경우 false 반환", () => {
72
- const parent = pathNorm("/parent/dir");
73
- const child = pathNorm("/parent/dir");
74
- expect(pathIsChildPath(child, parent)).toBe(false);
75
- });
76
-
77
- it("자식 경로가 아닌 경우 false 반환", () => {
78
- const parent = pathNorm("/parent/dir");
79
- const child = pathNorm("/other/dir/file.txt");
80
- expect(pathIsChildPath(child, parent)).toBe(false);
81
- });
82
-
83
- it("부모 경로의 일부 문자열만 일치하는 경우 false 반환", () => {
84
- const parent = pathNorm("/parent/dir");
85
- const child = pathNorm("/parent/directory/file.txt");
86
- expect(pathIsChildPath(child, parent)).toBe(false);
87
- });
88
- });
89
-
90
- //#endregion
91
-
92
- //#region changeFileDirectory
93
-
94
- describe("pathChangeFileDirectory", () => {
95
- it("파일의 디렉토리를 변경", () => {
96
- const file = pathNorm("/source/sub/file.txt");
97
- const from = pathNorm("/source");
98
- const to = pathNorm("/target");
99
-
100
- const result = pathChangeFileDirectory(file, from, to);
101
- expect(result).toBe(pathNorm("/target/sub/file.txt"));
102
- });
103
-
104
- it("중첩된 경로에서 디렉토리 변경", () => {
105
- const file = pathNorm("/a/b/c/d/file.txt");
106
- const from = pathNorm("/a/b");
107
- const to = pathNorm("/x/y");
108
-
109
- const result = pathChangeFileDirectory(file, from, to);
110
- expect(result).toBe(pathNorm("/x/y/c/d/file.txt"));
111
- });
112
-
113
- it("파일이 fromDirectory 안에 없으면 에러 발생", () => {
114
- const file = pathNorm("/other/path/file.txt");
115
- const from = pathNorm("/source");
116
- const to = pathNorm("/target");
117
-
118
- expect(() => pathChangeFileDirectory(file, from, to)).toThrow();
119
- });
120
-
121
- it("filePath와 fromDirectory가 동일한 경우 toDirectory 반환", () => {
122
- const file = pathNorm("/source");
123
- const from = pathNorm("/source");
124
- const to = pathNorm("/target");
125
-
126
- const result = pathChangeFileDirectory(file, from, to);
127
- expect(result).toBe(to);
128
- });
129
- });
130
-
131
- //#endregion
132
-
133
- //#region getBasenameWithoutExt
134
-
135
- describe("pathGetBasenameWithoutExt", () => {
136
- it("단일 확장자 제거 (basename만 반환)", () => {
137
- const result = pathGetBasenameWithoutExt("/path/to/file.txt");
138
- expect(result).toBe("file");
139
- });
140
-
141
- it("다중 확장자에서 마지막 확장자만 제거", () => {
142
- const result = pathGetBasenameWithoutExt("/path/to/file.spec.ts");
143
- expect(result).toBe("file.spec");
144
- });
145
-
146
- it("확장자가 없는 파일은 basename 반환", () => {
147
- const result = pathGetBasenameWithoutExt("/path/to/file");
148
- expect(result).toBe("file");
149
- });
150
-
151
- it("숨김 파일(점으로 시작)은 그대로 반환", () => {
152
- const result = pathGetBasenameWithoutExt("/path/to/.gitignore");
153
- expect(result).toBe(".gitignore");
154
- });
155
- });
156
-
157
- //#endregion
158
-
159
- //#region filterByTargets
160
-
161
- describe("pathFilterByTargets", () => {
162
- const cwd = "/proj";
163
- const files = ["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts", "/proj/lib/d.ts"];
164
-
165
- it("빈 타겟 배열이면 모든 파일 반환", () => {
166
- const result = pathFilterByTargets(files, [], cwd);
167
- expect(result).toEqual(files);
168
- });
169
-
170
- it("단일 타겟으로 필터링", () => {
171
- const result = pathFilterByTargets(files, ["src"], cwd);
172
- expect(result).toEqual(["/proj/src/a.ts", "/proj/src/b.ts"]);
173
- });
174
-
175
- it("다중 타겟으로 필터링", () => {
176
- const result = pathFilterByTargets(files, ["src", "tests"], cwd);
177
- expect(result).toEqual(["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts"]);
178
- });
179
-
180
- it("매칭되는 파일이 없으면 빈 배열 반환", () => {
181
- const result = pathFilterByTargets(files, ["nonexistent"], cwd);
182
- expect(result).toEqual([]);
183
- });
184
-
185
- it("정확한 파일 경로로 필터링", () => {
186
- const result = pathFilterByTargets(files, ["src/a.ts"], cwd);
187
- expect(result).toEqual(["/proj/src/a.ts"]);
188
- });
189
- });
190
-
191
- //#endregion
192
- });
@@ -1,35 +0,0 @@
1
- import { createWorker } from "../../../src";
2
-
3
- interface TestWorkerEvents extends Record<string, unknown> {
4
- progress: number;
5
- }
6
-
7
- const methods = {
8
- add: (a: number, b: number) => {
9
- sender.send("progress", 50);
10
- return a + b;
11
- },
12
- echo: (message: string) => `Echo: ${message}`,
13
- throwError: () => {
14
- throw new Error("Intentional error");
15
- },
16
- delay: async (ms: number) => {
17
- await new Promise((resolve) => setTimeout(resolve, ms));
18
- return ms;
19
- },
20
- noReturn: () => {},
21
- logMessage: (message: string) => {
22
- console.log(message);
23
- return "logged";
24
- },
25
- crash: () => {
26
- // 동기적으로 즉시 종료
27
- setImmediate(() => process.exit(1));
28
- return "crashing...";
29
- },
30
- getEnv: (key: string) => process.env[key],
31
- };
32
-
33
- const sender = createWorker<typeof methods, TestWorkerEvents>(methods);
34
-
35
- export default sender;
@@ -1,183 +0,0 @@
1
- import { afterEach, describe, expect, it } from "vitest";
2
- import path from "path";
3
- import type { WorkerProxy } from "../../src/worker/types";
4
- import { Worker } from "../../src/worker/worker";
5
- import type * as TestWorkerModule from "./fixtures/test-worker";
6
-
7
- describe("SdWorker", () => {
8
- const workerPath = path.resolve(import.meta.dirname, "fixtures/test-worker.ts");
9
- let worker: WorkerProxy<typeof TestWorkerModule> | undefined;
10
-
11
- afterEach(async () => {
12
- if (worker) {
13
- await worker.terminate();
14
- worker = undefined;
15
- }
16
- });
17
-
18
- //#region 메서드 호출
19
-
20
- describe("메서드 호출", () => {
21
- it("워커 메서드 호출 및 결과 반환", async () => {
22
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
23
-
24
- const result = await worker.add(10, 20);
25
-
26
- expect(result).toBe(30);
27
- });
28
-
29
- it("문자열 반환 메서드 호출", async () => {
30
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
31
-
32
- const result = await worker.echo("Hello");
33
-
34
- expect(result).toBe("Echo: Hello");
35
- });
36
-
37
- it("워커에서 에러 발생 시 reject", async () => {
38
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
39
-
40
- await expect(worker.throwError()).rejects.toThrow();
41
- });
42
-
43
- it("존재하지 않는 메서드 호출 시 에러", async () => {
44
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
45
-
46
- // 타입 시스템을 우회하여 존재하지 않는 메서드 호출
47
- const unknownWorker = worker as unknown as { unknownMethod: () => Promise<void> };
48
-
49
- await expect(unknownWorker.unknownMethod()).rejects.toThrow("알 수 없는 메서드: unknownMethod");
50
- });
51
-
52
- it("다중 요청 동시 처리", async () => {
53
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
54
-
55
- const [result1, result2, result3] = await Promise.all([worker.add(1, 2), worker.add(3, 4), worker.add(5, 6)]);
56
-
57
- expect(result1).toBe(3);
58
- expect(result2).toBe(7);
59
- expect(result3).toBe(11);
60
- });
61
-
62
- it("void 반환 메서드 호출", async () => {
63
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
64
-
65
- const result = await worker.noReturn();
66
-
67
- expect(result).toBeUndefined();
68
- });
69
- });
70
-
71
- //#endregion
72
-
73
- //#region 이벤트
74
-
75
- describe("이벤트", () => {
76
- it("워커에서 이벤트 수신", async () => {
77
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
78
-
79
- const events: number[] = [];
80
- worker.on("progress", (value) => {
81
- events.push(value);
82
- });
83
-
84
- await worker.add(1, 2);
85
-
86
- expect(events).toContain(50);
87
- });
88
-
89
- it("off()로 이벤트 리스너 제거", async () => {
90
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
91
-
92
- const events: number[] = [];
93
- const listener = (value: number) => {
94
- events.push(value);
95
- };
96
-
97
- worker.on("progress", listener);
98
- await worker.add(1, 2);
99
-
100
- // 리스너 제거
101
- worker.off("progress", listener);
102
- await worker.add(3, 4);
103
-
104
- // 첫 번째 호출의 이벤트만 수신되어야 함
105
- expect(events).toHaveLength(1);
106
- expect(events[0]).toBe(50);
107
- });
108
- });
109
-
110
- //#endregion
111
-
112
- //#region terminate
113
-
114
- describe("terminate", () => {
115
- it("대기 중인 요청이 Worker terminated 에러와 함께 reject", async () => {
116
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
117
-
118
- const runPromise = worker.delay(5000);
119
-
120
- // 워커 종료 전에 미리 에러를 캐치할 준비를 한다
121
- const errorPromise = runPromise.catch((err: unknown) => err);
122
-
123
- // 워커 종료
124
- await worker.terminate();
125
- worker = undefined;
126
-
127
- const error = await errorPromise;
128
- expect(error).toBeInstanceOf(Error);
129
- expect((error as Error).message).toBe("워커가 종료됨 (method: delay)");
130
- });
131
-
132
- it("워커 비정상 종료 시 대기 중인 요청 reject", async () => {
133
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
134
-
135
- // 긴 delay를 먼저 호출하여 pending 상태로 만듦
136
- const delayPromise = worker.delay(5000).catch((err: unknown) => err);
137
-
138
- // 짧은 대기 후 crash 호출 (delay가 pending 상태인 동안)
139
- await new Promise((resolve) => setTimeout(resolve, 10));
140
- await worker.crash();
141
-
142
- // 워커가 비정상 종료되면 pending 상태의 delay 요청이 reject되어야 함
143
- const error = await delayPromise;
144
- expect(error).toBeInstanceOf(Error);
145
- expect((error as Error).message).toContain("워커가 비정상 종료됨");
146
- });
147
- });
148
-
149
- //#endregion
150
-
151
- //#region stdout/stderr
152
-
153
- describe("stdout/stderr", () => {
154
- it("워커의 console.log 출력이 메인 프로세스로 전달", async () => {
155
- worker = Worker.create<typeof TestWorkerModule>(workerPath);
156
-
157
- const result = await worker.logMessage("test message");
158
-
159
- // 메서드가 정상 반환되면 stdout 파이핑이 동작한 것
160
- expect(result).toBe("logged");
161
- });
162
- });
163
-
164
- //#endregion
165
-
166
- //#region env 옵션
167
-
168
- describe("env 옵션", () => {
169
- it("env 옵션이 워커에 전달", async () => {
170
- worker = Worker.create<typeof TestWorkerModule>(workerPath, {
171
- env: {
172
- TEST_ENV_VAR: "test-value-123",
173
- },
174
- });
175
-
176
- const result = await worker.getEnv("TEST_ENV_VAR");
177
-
178
- expect(result).toBe("test-value-123");
179
- });
180
- });
181
-
182
- //#endregion
183
- });