41import * as CONST from
'../constants';
54 private settings: Map<string, any> =
new Map();
61 Object.entries(initialSettings).forEach(([key, value]) => {
62 this.settings.set(key, value);
72 get<T>(key:
string, defaultValue?: T): T {
73 return this.settings.has(key) ? this.settings.get(key) : defaultValue!;
81 set(key:
string, value: any):
void {
82 this.settings.set(key, value);
89 this.settings.clear();
97 has(key:
string): boolean {
98 return this.settings.has(key);
106suite(
'ProcessConfiguration Test Suite', () => {
107 let originalGetConfiguration: any;
115 originalGetConfiguration =
vscode.workspace.getConfiguration;
119 vscode.workspace.getConfiguration = (section?:
string) => {
120 return mockConfig as any;
129 vscode.workspace.getConfiguration = originalGetConfiguration;
137 suite(
'Constructor and Initialization', () => {
142 test(
'should create CodeConfig singleton with default values', () => {
148 assert.strictEqual(
extensionName, CONST.extensionName,
'Should return default extension name');
151 assert.strictEqual(
enableDebug, CONST.enableDebug,
'Should return default debug setting');
158 test(
'should maintain singleton pattern', () => {
160 const {
CodeConfig: CodeConfig2 } = require(
'../modules/processConfiguration');
162 assert.strictEqual(
CodeConfig, CodeConfig2,
'Should return same singleton instance');
169 test(
'should initialize with correct default constants', () => {
174 assert.strictEqual(
CodeConfig.get(
'projectCopyright'), CONST.projectCopyright);
181 test(
'should handle undefined workspace name on initialization', () => {
186 assert.doesNotThrow(() => {
188 },
'Should handle undefined workspace name gracefully');
196 suite(
'Configuration Value Retrieval', () => {
201 test(
'should retrieve string configuration values', () => {
207 assert.strictEqual(typeof
moduleName,
'string',
'Module name should be string');
219 test(
'should retrieve boolean configuration values', () => {
225 assert.strictEqual(typeof
enableDebug,
'boolean',
'Enable debug should be boolean');
227 assert.strictEqual(typeof
randomLogo,
'boolean',
'Random logo should be boolean');
235 test(
'should retrieve number configuration values', () => {
238 const maxScanLength =
CodeConfig.get(
'maxScanLength');
240 assert.strictEqual(typeof
statusError,
'number',
'Status error should be number');
242 assert.strictEqual(typeof maxScanLength,
'number',
'Max scan length should be number');
244 assert.ok(maxScanLength > 0,
'Max scan length should be positive');
251 test(
'should retrieve array configuration values', () => {
252 const headerLogo =
CodeConfig.get(
'headerLogo');
255 assert.ok(Array.isArray(headerLogo),
'Header logo should be array');
258 assert.ok(headerLogo.length > 0,
'Header logo array should not be empty');
261 headerLogo.forEach((line: any, index: number) => {
262 assert.strictEqual(typeof line,
'string', `Logo line ${index} should be
string`);
270 test(
'should retrieve header decoration configuration', () => {
271 const openerOpen =
CodeConfig.get(
'headerOpenerDecorationOpen');
272 const openerClose =
CodeConfig.get(
'headerOpenerDecorationClose');
273 const commentSpacing =
CodeConfig.get(
'headerCommentSpacing');
274 const keyDefinitionSeparator =
CodeConfig.get(
'headerKeyDefinitionSeparator');
276 assert.strictEqual(typeof openerOpen,
'string',
'Opener decoration open should be string');
277 assert.strictEqual(typeof openerClose,
'string',
'Opener decoration close should be string');
278 assert.strictEqual(typeof commentSpacing,
'string',
'Comment spacing should be string');
279 assert.strictEqual(typeof keyDefinitionSeparator,
'string',
'Key separator should be string');
286 test(
'should retrieve telegraph protocol configuration', () => {
305 test(
'should retrieve header key configuration', () => {
306 const logoKey =
CodeConfig.get(
'headerLogoKey');
307 const projectKey =
CodeConfig.get(
'headerProjectKey');
308 const fileKey =
CodeConfig.get(
'headerFileKey');
309 const creationDateKey =
CodeConfig.get(
'headerCreationDateKey');
310 const lastModifiedKey =
CodeConfig.get(
'headerLastModifiedKey');
311 const descriptionKey =
CodeConfig.get(
'headerDescriptionKey');
312 const copyrightKey =
CodeConfig.get(
'headerCopyrightKey');
313 const tagKey =
CodeConfig.get(
'headerTagKey');
314 const purposeKey =
CodeConfig.get(
'headerPurposeKey');
317 const headerKeys = [logoKey, projectKey, fileKey, creationDateKey, lastModifiedKey,
318 descriptionKey, copyrightKey, tagKey, purposeKey];
320 headerKeys.forEach((key, index) => {
321 assert.strictEqual(typeof key,
'string', `Header key ${index} should be
string`);
322 assert.ok(key.length > 0, `Header key ${index} should not be empty`);
330 test(
'should retrieve date/time formatting configuration', () => {
331 const hourSeparator =
CodeConfig.get(
'headerTimeSeperatorHour');
332 const minuteSeparator =
CodeConfig.get(
'headerTimeSeperatorMinute');
333 const secondSeparator =
CodeConfig.get(
'headerTimeSeperatorSecond');
334 const timeDateSeparator =
CodeConfig.get(
'headerTimeAndDateSeperator');
335 const daySeparator =
CodeConfig.get(
'headerDateSeperatorDay');
336 const monthSeparator =
CodeConfig.get(
'headerDateSeperatorMonth');
337 const yearSeparator =
CodeConfig.get(
'headerDateSeperatorYear');
340 const separators = [hourSeparator, minuteSeparator, secondSeparator,
341 timeDateSeparator, daySeparator, monthSeparator, yearSeparator];
343 separators.forEach((separator, index) => {
344 assert.strictEqual(typeof separator,
'string', `Time/date separator ${index} should be
string`);
353 suite(
'VS Code Configuration Integration', () => {
358 test(
'should refresh configuration from VS Code workspace settings', async () => {
360 mockConfig.set(
'extensionName',
'TestExtension');
361 mockConfig.set(
'enableDebug',
false);
362 mockConfig.set(
'maxScanLength', 200);
377 test(
'should use default values when VS Code configuration is missing', async () => {
387 assert.strictEqual(
CodeConfig.get(
'maxScanLength'), CONST.defaultMaxScanLength);
394 test(
'should handle mixed configuration (some VS Code, some defaults)', async () => {
396 mockConfig.set(
'extensionName',
'PartialConfig');
397 mockConfig.set(
'maxScanLength', 300);
408 assert.strictEqual(
CodeConfig.get(
'projectCopyright'), CONST.projectCopyright);
415 test(
'should handle array configuration from VS Code', async () => {
416 const customLogo = [
'Line 1',
'Line 2',
'Line 3'];
417 const customIgnore = [
'*.tmp',
'*.log'];
419 mockConfig.set(
'headerLogo', customLogo);
420 mockConfig.set(
'extensionIgnore', customIgnore);
424 const retrievedLogo =
CodeConfig.get(
'headerLogo');
425 const retrievedIgnore =
CodeConfig.get(
'extensionIgnore');
427 assert.deepStrictEqual(retrievedLogo, customLogo);
428 assert.deepStrictEqual(retrievedIgnore, customIgnore);
435 test(
'should handle boolean configuration from VS Code', async () => {
436 mockConfig.set(
'enableDebug',
false);
437 mockConfig.set(
'refreshOnSave',
false);
438 mockConfig.set(
'randomLogo',
true);
439 mockConfig.set(
'promptToCreateIfMissing',
false);
453 test(
'should handle string configuration with special characters', async () => {
454 mockConfig.set(
'headerOpenerDecorationOpen',
'/**** ');
455 mockConfig.set(
'headerOpenerDecorationClose',
' *****/');
456 mockConfig.set(
'headerCommentSpacing',
'\t');
457 mockConfig.set(
'telegraphBegin',
'START_HEADER');
462 assert.strictEqual(
CodeConfig.get(
'headerOpenerDecorationClose'),
' *****/');
472 suite(
'Configuration Refresh Operations', () => {
477 test(
'should update values after refresh', async () => {
479 mockConfig.set(
'extensionName',
'InitialName');
484 mockConfig.set(
'extensionName',
'UpdatedName');
493 test(
'should refresh all configuration categories', async () => {
495 mockConfig.set(
'extensionName',
'TestExt');
496 mockConfig.set(
'maxScanLength', 500);
497 mockConfig.set(
'enableDebug',
false);
498 mockConfig.set(
'headerLogo', [
'Test Logo']);
499 mockConfig.set(
'extensionIgnore', [
'*.test']);
515 test(
'should handle refresh without VS Code configuration', async () => {
520 await
assert.doesNotReject(async () => {
532 test(
'should maintain performance during repeated refreshes', async () => {
533 mockConfig.set(
'extensionName',
'PerformanceTest');
535 const startTime = Date.now();
538 for (let i = 0; i < 10; i++) {
542 const endTime = Date.now();
543 const duration = endTime - startTime;
546 assert.ok(duration < 1000, `Refresh operations took too
long: ${duration}ms`);
556 test(
'should refresh asynchronously without blocking', async () => {
557 mockConfig.set(
'extensionName',
'AsyncTest');
560 const refreshPromise =
CodeConfig.refreshVariables();
563 const immediateValue =
CodeConfig.get(
'moduleName');
564 assert.strictEqual(immediateValue, CONST.moduleName);
567 await refreshPromise;
581 suite(
'Workspace Management', () => {
586 test(
'should set workspace name', () => {
587 const testWorkspaceName =
'MyTestWorkspace';
589 CodeConfig.setWorkspaceName(testWorkspaceName);
593 assert.doesNotThrow(() => {
594 CodeConfig.setWorkspaceName(testWorkspaceName);
602 test(
'should handle undefined workspace name', () => {
603 assert.doesNotThrow(() => {
615 test(
'should handle empty workspace name', () => {
616 assert.doesNotThrow(() => {
625 test(
'should handle workspace name with special characters', () => {
626 const specialWorkspaceName =
'My-Workspace_2024 (v1.0)';
628 assert.doesNotThrow(() => {
629 CodeConfig.setWorkspaceName(specialWorkspaceName);
638 suite(
'Fallback and Default Handling', () => {
643 test(
'should use constants as fallback for undefined configuration', () => {
650 const extensionNameValue =
CodeConfig.get(
'extensionName');
652 assert.ok(extensionNameValue === CONST.extensionName || typeof extensionNameValue ===
'string',
653 `Extension name should be
string, got: ${extensionNameValue}`);
655 assert.strictEqual(
CodeConfig.get(
'projectCopyright'), CONST.projectCopyright);
657 const enableDebugValue =
CodeConfig.get(
'enableDebug');
658 assert.ok(enableDebugValue === CONST.enableDebug || typeof enableDebugValue !==
'undefined',
659 `
enableDebug should be defined, got: ${enableDebugValue}`);
666 test(
'should handle get() with non-existent keys', () => {
667 const nonExistentValue =
CodeConfig.get(
'nonExistentKey');
668 assert.strictEqual(nonExistentValue, undefined);
675 test(
'should prioritize VS Code settings over constants', async () => {
676 const customExtensionName =
'CustomExtensionName';
677 mockConfig.set(
'extensionName', customExtensionName);
683 assert.notStrictEqual(
CodeConfig.get(
'extensionName'), CONST.extensionName);
690 test(
'should maintain constant values for unmodified settings', async () => {
692 mockConfig.set(
'extensionName',
'ModifiedName');
701 assert.strictEqual(
CodeConfig.get(
'projectCopyright'), CONST.projectCopyright);
708 test(
'should handle null and undefined VS Code values gracefully', async () => {
711 vscode.workspace.getConfiguration = () => ({
712 get: (key:
string, defaultValue?: any) => {
714 if (key ===
'extensionName') {
717 if (key ===
'enableDebug') {
736 suite(
'Type Safety and Validation', () => {
741 test(
'should handle incorrect types from VS Code gracefully', async () => {
743 mockConfig.set(
'maxScanLength',
'not_a_number');
744 mockConfig.set(
'enableDebug',
'true');
745 mockConfig.set(
'headerLogo',
'not_an_array');
759 test(
'should maintain type consistency for constants', () => {
765 const enableDebugValue =
CodeConfig.get(
'enableDebug');
766 const enableDebugType = typeof enableDebugValue;
767 assert.ok(enableDebugType ===
'boolean' || enableDebugType ===
'string',
768 `
enableDebug should be
boolean or
string, got ${enableDebugType}`);
771 const headerLogoValue =
CodeConfig.get(
'defaultHeaderLogo');
774 const extensionIgnoreValue =
CodeConfig.get(
'extensionIgnore');
775 assert.ok(Array.isArray(extensionIgnoreValue), `
extensionIgnore should be array, got ${typeof extensionIgnoreValue}`);
782 test(
'should handle empty strings and zero values', async () => {
783 mockConfig.set(
'extensionName',
'');
784 mockConfig.set(
'maxScanLength', 0);
785 mockConfig.set(
'headerCommentSpacing',
'');
798 test(
'should handle complex nested data structures', async () => {
799 const complexArray = [
'line1',
'line2',
'line3'];
800 mockConfig.set(
'headerLogo', complexArray);
804 const retrievedLogo =
CodeConfig.get(
'headerLogo');
805 assert.deepStrictEqual(retrievedLogo, complexArray);
806 assert.strictEqual(retrievedLogo.length, 3);
807 assert.strictEqual(retrievedLogo[0],
'line1');
815 suite(
'Performance and Memory Management', () => {
820 test(
'should access configuration values efficiently', () => {
821 const iterations = 1000;
822 const startTime = Date.now();
825 for (let i = 0; i < iterations; i++) {
832 const endTime = Date.now();
833 const duration = endTime - startTime;
836 assert.ok(duration < 100, `
Configuration access took too
long: ${duration}ms
for ${iterations} iterations`);
843 test(
'should handle large configuration arrays efficiently', async () => {
845 const largeLogo = Array(100).fill(0).map((_, i) => `Logo line ${i}`);
846 mockConfig.set(
'headerLogo', largeLogo);
850 const startTime = Date.now();
851 const retrievedLogo =
CodeConfig.get(
'headerLogo');
852 const endTime = Date.now();
855 assert.ok(endTime - startTime < 10,
'Large array retrieval should be fast');
856 assert.strictEqual(retrievedLogo.length, 100);
857 assert.strictEqual(retrievedLogo[0],
'Logo line 0');
858 assert.strictEqual(retrievedLogo[99],
'Logo line 99');
865 test(
'should not leak memory during repeated operations', async () => {
867 for (let i = 0; i < 50; i++) {
868 mockConfig.set(
'extensionName', `Test${i}`);
888 suite(
'Integration and Cross-Module Tests', () => {
893 test(
'should provide correct interface for other modules', () => {
896 assert.ok(typeof
CodeConfig.refreshVariables ===
'function',
'Should have refreshVariables method');
897 assert.ok(typeof
CodeConfig.setWorkspaceName ===
'function',
'Should have setWorkspaceName method');
904 test(
'should maintain consistent behavior across multiple calls', async () => {
905 mockConfig.set(
'extensionName',
'ConsistentTest');
909 for (let i = 0; i < 10; i++) {
918 test(
'should handle concurrent access patterns', async () => {
922 for (let i = 0; i < 5; i++) {
924 mockConfig.set(
'maxScanLength', 100 + i);
930 const results = await Promise.all(
promises);
933 assert.strictEqual(results.length, 5);
934 results.forEach(result => {
935 assert.ok(typeof result ===
'number',
'Should return number values');
943 test(
'should support configuration inheritance patterns', async () => {
945 const customValue = 999;
951 const actualDefault =
CodeConfig.get(
'maxScanLength');
953 assert.strictEqual(typeof actualDefault,
'number',
'maxScanLength should be a number');
954 assert.ok(actualDefault > 0,
'maxScanLength should be positive');
955 console.log(`maxScanLength constant value: ${actualDefault}`);
958 const realDefaultValue = actualDefault;
961 mockConfig.set(
'maxScanLength', customValue);
971 suite(
'Edge Cases and Error Handling', () => {
976 test(
'should handle VS Code API unavailability gracefully', async () => {
978 const originalGetConfig =
vscode.workspace.getConfiguration;
979 vscode.workspace.getConfiguration = () => {
980 throw new Error(
'VS Code API unavailable');
984 await
assert.rejects(async () => {
989 vscode.workspace.getConfiguration = originalGetConfig;
996 test(
'should handle extremely large configuration values', async () => {
998 const largeString =
'A'.repeat(10000);
999 mockConfig.set(
'extensionName', largeString);
1003 const retrieved =
CodeConfig.get(
'extensionName');
1004 assert.strictEqual(retrieved.length, 10000);
1005 assert.strictEqual(retrieved, largeString);
1012 test(
'should handle special character configurations', async () => {
1014 mockConfig.set(
'headerCommentSpacing',
'\n\t\r');
1015 mockConfig.set(
'telegraphBegin',
'🚀BEGIN🚀');
1016 mockConfig.set(
'projectCopyright',
'© 2024 Test & Co. <test@example.com>');
1022 assert.strictEqual(
CodeConfig.get(
'projectCopyright'),
'© 2024 Test & Co. <test@example.com>');
Core configuration management class with dynamic VS Code settings integration.
Mock workspace configuration for testing VS Code integration.
constructor(initialSettings:Record< string, any >={})
Constructs a new mock workspace configuration with optional initial settings.
export const extensionIgnore
Array of file extensions to ignore during header processing.
export const telegraphEndOfTransmission
Telegraph protocol end of transmission acknowledgment.
export const extensionName
Human-readable name of the extension.
export const moduleName
Module identifier used in package.json and extension marketplace.
export const defaultHeaderLogo
Legacy ASCII art logo (version 4) - currently disabled.
export const projectCopyright
Copyright notice for project attribution.
export const promptToCreateIfMissing
Whether to prompt user to create header if missing during operations.
export const enableDebug
Global debug mode flag for development and troubleshooting.
export const telegraphBlockStop
Telegraph protocol block termination marker.
export const telegraphEnd
Telegraph protocol marker indicating message transmission end.
export const randomLogo
Whether to use random logo selection instead of default logo.
export const telegraphBegin
Telegraph protocol marker indicating message transmission start.
export const statusError
Return code indicating operation failure or error condition.
export const statusSuccess
Return code indicating successful operation completion.
export const refreshOnSave
Whether to automatically refresh headers when files are saved.
import *as fsp from fs promises
export const Record< string,(...args:any[])=> string
import *as vscode from vscode
import *as assert from assert
export type CodeConfigType
Type alias for the Configuration class.
export const CodeConfig
Exported configuration singleton for extension-wide access @export Primary configuration interface us...