39import {
CodeConfig } from
'../modules/processConfiguration';
53 appendLine: (message:
string) =>
void;
55 show: (preserveFocus?: boolean) =>
void;
78 public appendLineCallCount: number = 0;
79 public appendCallCount: number = 0;
80 public _lines:
string[] = [];
81 public _isVisible:
boolean =
false;
82 private _lastMessage:
string =
'';
96 append(value:
string): void {
97 this.appendCallCount++;
98 this._lastMessage += value;
99 this._lines.push(value);
106 appendLine(value:
string): void {
107 this.appendLineCallCount++;
108 this._lines.push(value);
109 this._lastMessage = value;
117 this.appendLineCallCount = 0;
118 this.appendCallCount = 0;
119 this._lastMessage =
'';
126 show(preserveFocus?:
boolean): void;
132 show(column?:
vscode.ViewColumn, preserveFocus?:
boolean): void;
138 show(columnOrPreserveFocus?: any, preserveFocus?:
boolean): void {
139 this._isVisible = true;
146 this._isVisible = false;
160 replace(value:
string): void {
161 this._lines = [value];
162 this._lastMessage = value;
169 getLastMessage():
string {
170 return this._lastMessage;
178 hasMessageContaining(substring:
string): boolean {
179 return this._lines.some(msg => msg.includes(substring));
188 subscriptions:
vscode.Disposable[];
190 globalState:
vscode.Memento & { setKeysForSync(keys: readonly
string[]): void; };
192 storagePath:
string | undefined;
196 environmentVariableCollection:
vscode.GlobalEnvironmentVariableCollection;
197 asAbsolutePath(relativePath:
string):
string;
204 languageModelAccessInformation:
vscode.LanguageModelAccessInformation;
211suite(
'Logger Test Suite', () => {
212 let originalCreateOutputChannel: typeof
vscode.window.createOutputChannel;
214 let originalConsoleLog: typeof console.log;
215 let originalConsoleWarn: typeof console.warn;
216 let originalConsoleError: typeof console.error;
217 let originalConsoleDebug: typeof console.debug;
218 let consoleLogCalls:
string[] = [];
219 let consoleWarnCalls:
string[] = [];
220 let consoleErrorCalls:
string[] = [];
221 let consoleDebugCalls:
string[] = [];
222 let originalShowInformationMessage: typeof
vscode.window.showInformationMessage;
223 let originalShowWarningMessage: typeof
vscode.window.showWarningMessage;
224 let originalShowErrorMessage: typeof
vscode.window.showErrorMessage;
225 let guiMessageCalls: {
type:
string; message:
string; items:
string[] }[] = [];
234 originalCreateOutputChannel =
vscode.window.createOutputChannel;
236 mockOutputChannel.name = name;
237 return mockOutputChannel as any;
241 consoleLogCalls = [];
242 consoleWarnCalls = [];
243 consoleErrorCalls = [];
244 consoleDebugCalls = [];
246 originalConsoleLog = console.log;
247 originalConsoleWarn = console.warn;
248 originalConsoleError = console.error;
249 originalConsoleDebug = console.debug;
251 console.log = (...args: any[]) => { consoleLogCalls.push(args.join(
' ')); };
252 console.warn = (...args: any[]) => { consoleWarnCalls.push(args.join(
' ')); };
253 console.error = (...args: any[]) => { consoleErrorCalls.push(args.join(
' ')); };
254 console.debug = (...args: any[]) => { consoleDebugCalls.push(args.join(
' ')); };
257 guiMessageCalls = [];
258 originalShowInformationMessage =
vscode.window.showInformationMessage;
259 originalShowWarningMessage =
vscode.window.showWarningMessage;
260 originalShowErrorMessage =
vscode.window.showErrorMessage;
262 vscode.window.showInformationMessage = <T extends
string>(message:
string, ...items: T[]) => {
263 guiMessageCalls.push({
type:
'info', message, items: items as
string[] });
264 return Promise.resolve(items[0]) as Thenable<T | undefined>;
267 vscode.window.showWarningMessage = <T extends
string>(message:
string, ...items: T[]) => {
268 guiMessageCalls.push({
type:
'warning', message, items: items as
string[] });
269 return Promise.resolve(items[0]) as Thenable<T | undefined>;
272 vscode.window.showErrorMessage = <T extends
string>(message:
string, ...items: T[]) => {
273 guiMessageCalls.push({
type:
'error', message, items: items as
string[] });
274 return Promise.resolve(items[0]) as Thenable<T | undefined>;
279 (
logger as any).output = mockOutputChannel;
282 if (
logger.Gui && typeof (
logger.Gui as any).updateLoadStatus ===
'function') {
283 (
logger.Gui as any).updateLoadStatus(
true);
287 process.env.VSCODE_DEBUG_MODE =
'true';
296 if (originalCreateOutputChannel) {
297 vscode.window.createOutputChannel = originalCreateOutputChannel;
299 if (originalShowInformationMessage) {
300 vscode.window.showInformationMessage = originalShowInformationMessage;
302 if (originalShowWarningMessage) {
303 vscode.window.showWarningMessage = originalShowWarningMessage;
305 if (originalShowErrorMessage) {
306 vscode.window.showErrorMessage = originalShowErrorMessage;
310 console.log = originalConsoleLog;
311 console.warn = originalConsoleWarn;
312 console.error = originalConsoleError;
313 console.debug = originalConsoleDebug;
316 mockOutputChannel._lines = [];
317 mockOutputChannel._isVisible =
false;
318 guiMessageCalls = [];
321 delete process.env.VSCODE_DEBUG_MODE;
328 suite(
'LoggerInternals Utility Class', () => {
333 test(
'should generate correct log level prefixes', () => {
335 const logInstance =
new (
logger.constructor as any)();
336 const internals = logInstance.LI;
338 assert.strictEqual(internals.getCorrectPrefix(
true,
false,
false,
false),
"INFO: ");
339 assert.strictEqual(internals.getCorrectPrefix(
false,
true,
false,
false),
"WARNING: ");
340 assert.strictEqual(internals.getCorrectPrefix(
false,
false,
true,
false),
"ERROR: ");
341 assert.strictEqual(internals.getCorrectPrefix(
false,
false,
false,
true),
"DEBUG: ");
342 assert.strictEqual(internals.getCorrectPrefix(
false,
false,
false,
false),
"");
349 test(
'should prioritize prefix types correctly', () => {
350 const logInstance =
new (
logger.constructor as any)();
351 const internals = logInstance.LI;
354 assert.strictEqual(internals.getCorrectPrefix(
true,
true,
true,
true),
"INFO: ");
355 assert.strictEqual(internals.getCorrectPrefix(
false,
true,
true,
true),
"WARNING: ");
356 assert.strictEqual(internals.getCorrectPrefix(
false,
false,
true,
true),
"ERROR: ");
363 test(
'should generate properly formatted timestamps', () => {
364 const logInstance =
new (
logger.constructor as any)();
365 const internals = logInstance.LI;
367 const timestamp = internals.getDatetime();
370 assert.ok(timestamp.startsWith(
'['),
'Timestamp should start with [');
371 assert.ok(timestamp.endsWith(
']'),
'Timestamp should end with ]');
374 const innerTimestamp = timestamp.slice(1, -1);
375 const parts = innerTimestamp.split(
' ');
376 assert.strictEqual(parts.length, 2,
'Timestamp should have date and time parts');
379 const dateParts = parts[0].split(
'-');
380 assert.strictEqual(dateParts.length, 3,
'Date should have 3 parts');
383 const timeParts = parts[1].split(
':');
384 assert.strictEqual(timeParts.length, 3,
'Time should have 3 parts');
385 assert.ok(timeParts[2].includes(
'.'),
'Seconds should include milliseconds');
392 test(
'should handle timestamp generation under load', () => {
393 const logInstance =
new (
logger.constructor as any)();
394 const internals = logInstance.LI;
396 const timestamps = [];
397 for (let i = 0; i < 100; i++) {
398 timestamps.push(internals.getDatetime());
402 timestamps.forEach(ts => {
403 assert.ok(ts.startsWith(
'[') && ts.endsWith(
']'),
'All timestamps should be properly formatted');
407 const uniqueTimestamps =
new Set(timestamps);
408 assert.ok(uniqueTimestamps.size >= 1,
'Should generate valid timestamps');
415 test(
'should identify parent caller correctly', () => {
416 const logInstance =
new (
logger.constructor as any)();
417 const internals = logInstance.LI;
419 function testFunction() {
420 return internals.getParentCaller(2);
423 function wrapperFunction() {
424 return testFunction();
427 const caller = wrapperFunction();
429 if (caller !== undefined) {
430 assert.ok(typeof caller ===
'string',
'Caller should be a string when resolved');
431 assert.ok(caller.length > 0,
'Caller name should not be empty');
439 test(
'should handle different search depths for caller identification', () => {
440 const logInstance =
new (
logger.constructor as any)();
441 const internals = logInstance.LI;
443 function deepFunction() {
445 depth1: internals.getParentCaller(1),
446 depth2: internals.getParentCaller(2),
447 depth3: internals.getParentCaller(3),
448 depth10: internals.getParentCaller(10)
452 const results = deepFunction();
455 Object.values(results).forEach(result => {
456 if (result !== undefined) {
457 assert.ok(typeof result ===
'string',
'Valid caller should be a string');
466 test(
'should handle debug enabled configuration correctly', () => {
467 const logInstance =
new (
logger.constructor as any)();
468 const internals = logInstance.LI;
470 const debugEnabled = internals.debugEnabled();
471 assert.ok(typeof debugEnabled ===
'boolean',
'Debug enabled should return boolean');
478 test(
'should detect extension installation state', () => {
479 const logInstance =
new (
logger.constructor as any)();
480 const internals = logInstance.LI;
483 const installedUndefined = internals.checkIfExtensionInstalled(undefined);
484 assert.ok(typeof installedUndefined ===
'boolean',
'Should return boolean for undefined context');
491 assert.strictEqual(internals.checkIfExtensionInstalled(developmentContext),
false,
'Development mode should return false');
492 assert.strictEqual(internals.checkIfExtensionInstalled(testContext),
false,
'Test mode should return false');
493 assert.strictEqual(internals.checkIfExtensionInstalled(productionContext),
true,
'Production mode should return true');
501 suite(
'Gui Notification System', () => {
506 test(
'should display information notifications', async () => {
507 const result = await
logger.Gui.info(
"Test information message");
509 assert.strictEqual(guiMessageCalls.length, 1,
'Should make one GUI call');
510 assert.strictEqual(guiMessageCalls[0].
type,
'info',
'Should be info type');
511 assert.strictEqual(guiMessageCalls[0].message,
"Test information message",
'Should pass message correctly');
518 test(
'should display information notifications with buttons', async () => {
519 const result = await
logger.Gui.info(
"Choose option",
"Yes",
"No",
"Cancel");
521 assert.strictEqual(guiMessageCalls.length, 1,
'Should make one GUI call');
522 assert.strictEqual(guiMessageCalls[0].
type,
'info',
'Should be info type');
523 assert.deepStrictEqual(guiMessageCalls[0].items, [
"Yes",
"No",
"Cancel"],
'Should pass buttons correctly');
530 test(
'should display warning notifications', async () => {
531 const result = await
logger.Gui.warning(
"Test warning message");
533 assert.strictEqual(guiMessageCalls.length, 1,
'Should make one GUI call');
534 assert.strictEqual(guiMessageCalls[0].
type,
'warning',
'Should be warning type');
535 assert.strictEqual(guiMessageCalls[0].message,
"Test warning message",
'Should pass message correctly');
542 test(
'should display warning notifications with buttons', async () => {
543 const result = await
logger.Gui.warning(
"Warning with options",
"Retry",
"Cancel");
545 assert.strictEqual(guiMessageCalls.length, 1,
'Should make one GUI call');
546 assert.deepStrictEqual(guiMessageCalls[0].items, [
"Retry",
"Cancel"],
'Should pass buttons correctly');
553 test(
'should display error notifications', async () => {
554 const result = await
logger.Gui.error(
"Test error message");
556 assert.strictEqual(guiMessageCalls.length, 1,
'Should make one GUI call');
557 assert.strictEqual(guiMessageCalls[0].
type,
'error',
'Should be error type');
558 assert.strictEqual(guiMessageCalls[0].message,
"Test error message",
'Should pass message correctly');
565 test(
'should display error notifications with buttons', async () => {
566 const result = await
logger.Gui.error(
"Critical error",
"Retry",
"Report",
"Close");
568 assert.strictEqual(guiMessageCalls.length, 1,
'Should make one GUI call');
569 assert.deepStrictEqual(guiMessageCalls[0].items, [
"Retry",
"Report",
"Close"],
'Should pass buttons correctly');
576 test(
'should handle debug notifications based on debug configuration', async () => {
580 if (key ===
"enableDebug") {
586 const result = await
logger.Gui.debug(
"Debug message",
"OK");
588 assert.strictEqual(guiMessageCalls.length, 1,
'Should show debug notification when debug enabled');
591 guiMessageCalls = [];
593 if (key ===
"enableDebug") {
599 const result2 = await
logger.Gui.debug(
"Debug message 2",
"OK");
601 assert.strictEqual(guiMessageCalls.length, 0,
'Should not show debug notification when debug disabled');
611 test(
'should handle empty button arrays', async () => {
612 await
logger.Gui.info(
"Message without buttons");
613 await
logger.Gui.warning(
"Warning without buttons");
614 await
logger.Gui.error(
"Error without buttons");
616 assert.strictEqual(guiMessageCalls.length, 3,
'Should handle messages without buttons');
617 guiMessageCalls.forEach(call => {
618 assert.deepStrictEqual(call.items, [],
'Items should be empty array when no buttons provided');
626 test(
'should handle special characters in messages', async () => {
627 const specialMessage =
"Message with special chars: !@#$%^&*(){}[]|\\:;\"'<>?,./ and unicode: 🚀 ✨ 💯";
628 await
logger.Gui.info(specialMessage);
630 assert.strictEqual(guiMessageCalls.length, 1,
'Should have one message call');
631 assert.strictEqual(guiMessageCalls[0]?.message, specialMessage,
'Should handle special characters correctly');
639 suite(
'Log Main Controller', () => {
644 test(
'should log info messages to output channel', () => {
645 logger.info(
"Test info message");
647 assert.ok(mockOutputChannel._lines.length > 0,
'Should write to output channel');
648 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
650 assert.ok(logLine.includes(
'INFO:'),
'Should include INFO prefix');
651 assert.ok(logLine.includes(
'Test info message'),
'Should include message text');
652 assert.ok(logLine.match(/\[\d{1,2}-\d{1,2}-\d{4} \d{1,2}:\d{1,2}:\d{1,2}\.\d{1,3}\]/),
'Should include timestamp');
659 test(
'should log warning messages to output channel', () => {
660 logger.warning(
"Test warning message");
662 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
664 assert.ok(logLine.includes(
'WARNING:'),
'Should include WARNING prefix');
665 assert.ok(logLine.includes(
'Test warning message'),
'Should include message text');
672 test(
'should log error messages to output channel', () => {
673 logger.error(
"Test error message");
675 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
677 assert.ok(logLine.includes(
'ERROR:'),
'Should include ERROR prefix');
678 assert.ok(logLine.includes(
'Test error message'),
'Should include message text');
685 test(
'should log debug messages to output channel', () => {
689 if (key ===
"enableDebug") {
695 const initialLineCount = mockOutputChannel._lines.length;
696 logger.debug(
"Test debug message");
702 assert.ok(mockOutputChannel._lines.length > initialLineCount,
'Should add debug message to output channel when debug is enabled');
704 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
705 assert.ok(logLine && logLine.includes(
'DEBUG:'),
'Should include DEBUG prefix');
706 assert.ok(logLine && logLine.includes(
'Test debug message'),
'Should include message text');
713 test(
'should include caller information in log messages', () => {
714 function testCaller() {
715 logger.info(
"Message from test caller");
720 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
721 assert.ok(logLine.includes(
'<'),
'Should include caller brackets');
722 assert.ok(logLine.includes(
'>'),
'Should include caller brackets');
729 test(
'should handle custom search depth for caller identification', () => {
730 function deepFunction() {
731 logger.info(
"Deep message", 4);
734 function wrapperFunction() {
738 function outerWrapper() {
744 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
745 assert.ok(logLine.includes(
'<'),
'Should include caller information with custom depth');
752 test(
'should handle multiple rapid log calls', () => {
753 const initialCount = mockOutputChannel._lines.length;
755 for (let i = 0; i < 100; i++) {
756 logger.info(`Rapid message ${i}`);
759 assert.strictEqual(mockOutputChannel._lines.length - initialCount, 100,
'Should handle all rapid log calls');
762 const messages = mockOutputChannel._lines.slice(initialCount);
763 for (let i = 0; i < 100; i++) {
764 assert.ok(
messages[i].includes(`Rapid message ${i}`), `Should include message ${i}`);
772 test(
'should handle very long messages', () => {
773 const longMessage =
"A".repeat(10000);
776 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
777 assert.ok(logLine.includes(longMessage),
'Should handle very long messages');
784 test(
'should handle messages with newlines and special characters', () => {
785 const complexMessage =
"Message with\nnewlines and\ttabs and 'quotes' and \"double quotes\"";
786 logger.info(complexMessage);
788 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
789 assert.ok(logLine.includes(complexMessage),
'Should handle complex messages with special characters');
797 suite(
'Console Output Behavior', () => {
802 test(
'console mock should work', () => {
805 const initialCount = mockOutputChannel.appendLineCallCount;
806 logger.info(
'Console mock test message');
809 assert.strictEqual(mockOutputChannel.appendLineCallCount, initialCount + 1,
'Message should be sent to output channel');
810 assert.ok(mockOutputChannel.getLastMessage()?.includes(
'Console mock test message'),
'Output channel should contain test message');
817 test(
'should output to console in development mode', () => {
820 const devLogger =
new (
logger.constructor as any)(devContext);
823 (devLogger as any).output = mockOutputChannel;
826 assert.strictEqual((devLogger as any).extensionInstalled,
false,
'Logger should be in development mode (extensionInstalled should be false)');
829 mockOutputChannel.clear();
831 devLogger.info(
"Development mode message");
836 const outputLines = mockOutputChannel._lines;
837 assert.ok(outputLines.length > 0,
'Should output to output channel');
839 const lastLine = outputLines[outputLines.length - 1];
840 assert.ok(lastLine.includes(
'INFO:'),
'Should include INFO prefix in output');
841 assert.ok(lastLine.includes(
'Development mode message'),
'Should include message content in output');
848 test(
'should not output to console in production mode', () => {
851 const prodLogger =
new (
logger.constructor as any)(prodContext);
853 const initialConsoleCount = consoleLogCalls.length;
854 prodLogger.info(
"Production mode message");
856 assert.strictEqual(consoleLogCalls.length, initialConsoleCount,
'Should not output to console in production mode');
863 test(
'should use appropriate console methods for different log levels', () => {
871 if (key ===
"enableDebug") {
879 const devLogger =
new (
logger.constructor as any)(devContext);
882 (devLogger as any).output = mockOutputChannel;
885 mockOutputChannel.clear();
888 devLogger.info(
"Test info message");
889 devLogger.warning(
"Test warning message");
890 devLogger.error(
"Test error message");
891 devLogger.debug(
"Test debug message");
897 const outputLines = mockOutputChannel._lines;
900 assert.strictEqual(outputLines.length, 4,
'Should have logged 4 messages to output channel');
903 const infoLine = outputLines.find(line => line.includes(
'Test info message'));
904 const warningLine = outputLines.find(line => line.includes(
'Test warning message'));
905 const errorLine = outputLines.find(line => line.includes(
'Test error message'));
906 const debugLine = outputLines.find(line => line.includes(
'Test debug message'));
908 assert.ok(infoLine && infoLine.includes(
'INFO:'),
'Info message should have INFO prefix');
909 assert.ok(warningLine && warningLine.includes(
'WARNING:'),
'Warning message should have WARNING prefix');
910 assert.ok(errorLine && errorLine.includes(
'ERROR:'),
'Error message should have ERROR prefix');
911 assert.ok(debugLine && debugLine.includes(
'DEBUG:'),
'Debug message should have DEBUG prefix');
923 suite(
'Output Channel Management', () => {
928 test(
'should create output channel with correct name', () => {
930 assert.ok(mockOutputChannel.name,
'Output channel should have a name');
937 test(
'should show output channel in development mode', (done) => {
940 const testLogger =
new (
logger.constructor as any)(devContext,
true);
944 assert.strictEqual(mockOutputChannel._isVisible,
true,
'Output channel should be visible in development mode');
953 test(
'should not auto-show output channel in production mode', () => {
955 mockOutputChannel._isVisible =
false;
959 new (
logger.constructor as any)(prodContext);
961 assert.strictEqual(mockOutputChannel._isVisible,
false,
'Output channel should not auto-show in production mode');
968 test(
'should update installation state dynamically', (done) => {
970 const testLogger =
new (
logger.constructor as any)(undefined,
true);
974 testLogger.updateInstallationState(devContext);
978 testLogger.updateInitialisationStatus(
true);
982 assert.strictEqual(mockOutputChannel._isVisible,
true,
'Should show output channel when updated to development mode');
992 suite(
'Singleton Behavior', () => {
997 test(
'should export singleton logger instance', () => {
999 assert.ok(typeof
logger.info ===
'function',
'Logger should have info method');
1000 assert.ok(typeof
logger.warning ===
'function',
'Logger should have warning method');
1001 assert.ok(typeof
logger.error ===
'function',
'Logger should have error method');
1002 assert.ok(typeof
logger.debug ===
'function',
'Logger should have debug method');
1009 test(
'should have consistent behavior across calls', () => {
1010 const initialLineCount = mockOutputChannel._lines.length;
1012 logger.info(
"First message");
1013 logger.info(
"Second message");
1015 assert.strictEqual(mockOutputChannel._lines.length - initialLineCount, 2,
'Should log both messages');
1017 const firstLine = mockOutputChannel._lines[initialLineCount];
1018 const secondLine = mockOutputChannel._lines[initialLineCount + 1];
1021 assert.ok(firstLine.includes(
'INFO:') && secondLine.includes(
'INFO:'),
'Both should have INFO prefix');
1022 assert.ok(firstLine.includes(
'First message') && secondLine.includes(
'Second message'),
'Should include respective messages');
1029 test(
'should maintain Gui instance accessibility', () => {
1030 assert.ok(
logger.Gui,
'Logger should have Gui instance');
1031 assert.ok(typeof
logger.Gui.info ===
'function',
'Gui should have info method');
1032 assert.ok(typeof
logger.Gui.warning ===
'function',
'Gui should have warning method');
1033 assert.ok(typeof
logger.Gui.error ===
'function',
'Gui should have error method');
1034 assert.ok(typeof
logger.Gui.debug ===
'function',
'Gui should have debug method');
1042 suite(
'Integration and Configuration', () => {
1047 test(
'should integrate with CodeConfig for extension name', () => {
1048 logger.info(
"Config test message");
1050 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
1063 test(
'should respect debug configuration for GUI debug messages', async () => {
1066 let debugEnabled =
true;
1069 if (key ===
"enableDebug") {
1070 return debugEnabled;
1076 await
logger.Gui.debug(
"Debug GUI message");
1077 assert.strictEqual(guiMessageCalls.length, 1,
'Should show debug GUI message when enabled');
1080 guiMessageCalls = [];
1081 debugEnabled =
false;
1082 await
logger.Gui.debug(
"Debug GUI message 2");
1083 assert.strictEqual(guiMessageCalls.length, 0,
'Should not show debug GUI message when disabled');
1093 test(
'should handle configuration errors gracefully', () => {
1097 if (key ===
"extensionName") {
1098 throw new Error(
"Config error");
1105 logger.info(
"Test message with config error");
1108 assert.ok(error instanceof Error,
'Should handle config errors');
1120 suite(
'Error Handling and Edge Cases', () => {
1125 test(
'should handle undefined and null messages', () => {
1126 logger.info(undefined as any);
1127 logger.warning(
null as any);
1130 assert.ok(mockOutputChannel._lines.length >= 3,
'Should handle undefined/null/empty messages without crashing');
1137 test(
'should handle very deep call stacks', () => {
1138 function createDeepStack(depth: number): any {
1140 return logger.info(
"Deep stack message");
1142 return createDeepStack(depth - 1);
1146 createDeepStack(50);
1148 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
1149 assert.ok(logLine.includes(
'Deep stack message'),
'Should handle deep call stacks');
1152 assert.ok(error instanceof Error,
'Should handle stack overflow gracefully');
1160 test(
'should handle concurrent logging operations', async () => {
1162 const initialCount = mockOutputChannel._lines.length;
1165 for (let i = 0; i < 50; i++) {
1166 promises.push(Promise.resolve().then(() => {
1167 logger.info(`Concurrent message ${i}`);
1168 return logger.Gui.info(`GUI message ${i}`);
1174 assert.ok(mockOutputChannel._lines.length >= initialCount + 50,
'Should handle concurrent logging operations');
1181 test(
'should handle extremely long caller names', () => {
1183 const longFunctionNameThatExceedsNormalLimitsAndTestsEdgeCasesInCallerIdentification =
function () {
1184 logger.info(
"Message from long-named function");
1187 longFunctionNameThatExceedsNormalLimitsAndTestsEdgeCasesInCallerIdentification();
1189 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
1190 assert.ok(logLine.includes(
'<') && logLine.includes(
'>'),
'Should handle long function names');
1197 test(
'should handle messages with various encodings', () => {
1200 "Unicode message: 🌟 ✨ 🚀",
1201 "Cyrillic: Привет мир",
1203 "Arabic: مرحبا بالعالم",
1204 "Emoji mix: Hello 👋 World 🌍"
1209 const logLine = mockOutputChannel._lines[mockOutputChannel._lines.length - 1];
1210 assert.ok(logLine.includes(msg), `Should handle message encoding ${index}`);
1219 suite(
'Performance and Memory', () => {
1224 test(
'should handle high-frequency logging efficiently', () => {
1225 const startTime = Date.now();
1226 const initialCount = mockOutputChannel._lines.length;
1228 for (let i = 0; i < 1000; i++) {
1229 logger.info(`High frequency message ${i}`);
1232 const elapsed = Date.now() - startTime;
1233 const finalCount = mockOutputChannel._lines.length;
1235 assert.strictEqual(finalCount - initialCount, 1000,
'Should log all messages');
1236 assert.ok(elapsed < 5000,
'Should complete high-frequency logging within reasonable time');
1243 test(
'should not leak memory during repeated operations', () => {
1245 mockOutputChannel.clear();
1247 for (let i = 0; i < 100; i++) {
1248 logger.info(`Memory test message ${i}`);
1252 mockOutputChannel.clear();
1257 assert.ok(
true,
'Should handle repeated operations without memory issues');
1264 test(
'should handle rapid GUI notifications efficiently', async () => {
1265 const startTime = Date.now();
1268 for (let i = 0; i < 100; i++) {
1273 const elapsed = Date.now() - startTime;
1275 assert.strictEqual(guiMessageCalls.length, 100,
'Should handle all GUI messages');
1276 assert.ok(elapsed < 3000,
'Should handle rapid GUI notifications efficiently');
1284 suite(
'Type Safety and Interface Compliance', () => {
1289 test(
'should maintain LogType interface compatibility', () => {
1293 assert.ok(typeof typedLogger.info ===
'function',
'Should implement info method');
1294 assert.ok(typeof typedLogger.warning ===
'function',
'Should implement warning method');
1295 assert.ok(typeof typedLogger.error ===
'function',
'Should implement error method');
1296 assert.ok(typeof typedLogger.debug ===
'function',
'Should implement debug method');
1297 assert.ok(typedLogger.Gui,
'Should have Gui property');
1304 test(
'should handle type-safe GUI button interactions', async () => {
1306 const result1 = await
logger.Gui.info(
"Test",
"Option1",
"Option2");
1307 const result2 = await
logger.Gui.warning(
"Test");
1308 const result3 = await
logger.Gui.error(
"Test",
"Retry");
1311 assert.ok(result1 ===
"Option1" || result1 === undefined,
'Should return proper button type');
1312 assert.ok(result2 === undefined,
'Should return undefined for no buttons');
1313 assert.ok(result3 ===
"Retry" || result3 === undefined,
'Should return proper button type');
1321 suite(
'Environment Variable Integration', () => {
1326 test(
'should handle VSCODE_DEBUG_MODE environment variable', () => {
1328 const originalEnv = process.env.VSCODE_DEBUG_MODE;
1331 process.env.VSCODE_DEBUG_MODE =
'true';
1332 const testLogger1 =
new (
logger.constructor as any)(undefined);
1335 process.env.VSCODE_DEBUG_MODE =
'false';
1336 const testLogger2 =
new (
logger.constructor as any)(undefined);
1339 if (originalEnv !== undefined) {
1340 process.env.VSCODE_DEBUG_MODE = originalEnv;
1342 delete process.env.VSCODE_DEBUG_MODE;
1345 assert.ok(
true,
'Should handle environment variable configuration');
Mock implementation for testing output channel behavior.
constructor(name:string)
Constructs a new mock output channel with specified name.
export const extensionName
Human-readable name of the extension.
import *as vscode from vscode
Mock VS Code extension context for testing.
Mock implementation of VS Code OutputChannel for testing logging behavior.
import *as fsp from fs promises
import *as vscode from vscode
import *as assert from assert
asAbsolutePath(relativePath:string) storageUri
export const logger
Singleton logger instance providing unified logging interface for the entire extension.
export type LogType
Type alias for Log class enabling dependency injection and testing.
export const messages
Complete message dictionary for all supported languages with type-safe function interfaces @export Ex...
export const Record< string,(...args:any[])=> string
export const CodeConfig
Exported configuration singleton for extension-wide access @export Primary configuration interface us...