UNPKG

@akala/core

Version:
443 lines 17.3 kB
import { it } from 'node:test'; import assert from 'assert'; import { LogLevels, LoggerMiddleware, LogMiddlewareWrapper, LoggerAdapterMiddleware, configureLogging, logConfig, } from '../logging/shared.js'; import { ConsoleLogger } from '../logging/sync/console.js'; import { LoggerLogMiddlewareWrapper } from '../logging/sync/wrapper.js'; // Test suite: LogLevels enum it('LogLevels should have correct numeric values', () => { assert.strictEqual(LogLevels.error, 0); assert.strictEqual(LogLevels.warn, 1); assert.strictEqual(LogLevels.help, 2); assert.strictEqual(LogLevels.data, 3); assert.strictEqual(LogLevels.info, 4); assert.strictEqual(LogLevels.debug, 5); assert.strictEqual(LogLevels.prompt, 6); assert.strictEqual(LogLevels.verbose, 7); assert.strictEqual(LogLevels.input, 8); assert.strictEqual(LogLevels.silly, 9); }); // Test suite: LoggerMiddleware it('LoggerMiddleware should call handler when shouldHandle returns true', () => { let handlerCalled = false; const handler = () => { handlerCalled = true; }; const middleware = new LoggerMiddleware(handler, LogLevels.info, 'app'); middleware.handle(LogLevels.error, ['app']); assert.ok(handlerCalled, 'Handler should be called when shouldHandle returns true'); }); it('LoggerMiddleware should not call handler when log level is too low', () => { let handlerCalled = false; const handler = () => { handlerCalled = true; }; const middleware = new LoggerMiddleware(handler, LogLevels.debug, '*'); const result = middleware.handle(LogLevels.silly, ['test']); assert.ok(!handlerCalled, 'Handler should not be called when log level is too low'); assert.strictEqual(result, undefined); }); it('LoggerMiddleware should not call handler when namespace does not match', () => { let handlerCalled = false; const handler = () => { handlerCalled = true; }; const middleware = new LoggerMiddleware(handler, LogLevels.error, 'app'); const result = middleware.handle(LogLevels.error, ['other']); assert.ok(!handlerCalled, 'Handler should not be called when namespace does not match'); assert.strictEqual(result, undefined); }); it('LoggerMiddleware should call handler with wildcard namespace', () => { let handlerCalled = false; const handler = () => { handlerCalled = true; }; const middleware = new LoggerMiddleware(handler, LogLevels.info, '*'); middleware.handle(LogLevels.error, ['arbitrary', 'namespace']); // With wildcard, namespace matches and level allows, so handler is called assert.ok(handlerCalled); }); it('LoggerMiddleware.shouldHandle should return true when conditions are met', () => { const handler = () => { }; const middleware = new LoggerMiddleware(handler, LogLevels.warn, 'app'); assert.ok(middleware.shouldHandle(LogLevels.warn, ['app'])); assert.ok(middleware.shouldHandle(LogLevels.error, ['app'])); }); it('LoggerMiddleware.shouldHandle should return false when log level is too low', () => { const handler = () => { }; const middleware = new LoggerMiddleware(handler, LogLevels.warn, 'app'); assert.ok(!middleware.shouldHandle(LogLevels.info, ['app'])); }); it('LoggerMiddleware.shouldHandle should return false for non-matching namespace', () => { const handler = () => { }; const middleware = new LoggerMiddleware(handler, LogLevels.error, 'app'); assert.ok(!middleware.shouldHandle(LogLevels.error, ['other'])); }); it('LoggerMiddleware should pass all arguments to handler when shouldHandle is true', () => { const capturedArgs = []; const handler = (logLevel, namespaces, ...args) => { capturedArgs.push(logLevel, namespaces, ...args); }; const middleware = new LoggerMiddleware(handler, LogLevels.debug, 'app'); const testValue = { key: 'value' }; // Matching namespace and sufficient level triggers handler middleware.handle(LogLevels.debug, ['app'], 'message', testValue, 42); assert.strictEqual(capturedArgs[0], LogLevels.debug); assert.deepStrictEqual(capturedArgs[1], ['app']); assert.strictEqual(capturedArgs[2], 'message'); assert.deepStrictEqual(capturedArgs[3], testValue); assert.strictEqual(capturedArgs[4], 42); }); it('LoggerMiddleware should have public properties for logLevel and namespace', () => { const handler = () => { }; const middleware = new LoggerMiddleware(handler, LogLevels.warn, 'testNamespace'); assert.strictEqual(middleware.logLevel, LogLevels.warn); assert.strictEqual(middleware.namespace, 'testNamespace'); }); // Test suite: LogMiddlewareWrapper it('LogMiddlewareWrapper should delegate to wrapped logger when conditions match', () => { let delegateCalled = false; const mockLogger = { handle: () => { delegateCalled = true; }, shouldHandle: () => true, }; const wrapper = new LogMiddlewareWrapper(mockLogger, LogLevels.error, 'app'); // error (0) matches, app matches, wrapped logger says yes wrapper.handle(LogLevels.error, ['app']); assert.ok(delegateCalled, 'Should delegate to wrapped logger when all conditions match'); }); it('LogMiddlewareWrapper should not delegate when log level is too low', () => { let delegateCalled = false; const mockLogger = { handle: () => { delegateCalled = true; }, shouldHandle: () => true, }; const wrapper = new LogMiddlewareWrapper(mockLogger, LogLevels.debug, 'app'); // debug (5) < silly (9), so shouldHandle returns false const result = wrapper.handle(LogLevels.silly, ['app']); assert.ok(!delegateCalled, 'Should not delegate when log level is too low'); assert.strictEqual(result, undefined); }); it('LogMiddlewareWrapper should not delegate when namespace does not match', () => { let delegateCalled = false; const mockLogger = { handle: () => { delegateCalled = true; }, shouldHandle: () => true, }; const wrapper = new LogMiddlewareWrapper(mockLogger, LogLevels.error, 'app'); const result = wrapper.handle(LogLevels.error, ['other']); assert.ok(!delegateCalled, 'Should not delegate when namespace does not match'); assert.strictEqual(result, undefined); }); it('LogMiddlewareWrapper.shouldHandle should check level first', () => { const mockLogger = { handle: () => { }, shouldHandle: () => true, }; const wrapper = new LogMiddlewareWrapper(mockLogger, LogLevels.debug, 'app'); // Should return false when level condition fails assert.ok(!wrapper.shouldHandle(LogLevels.silly, ['app'])); }); it('LogMiddlewareWrapper.shouldHandle should check namespace and delegate to wrapped logger', () => { let delegateChecked = false; const wrappedShouldHandle = (level, namespaces) => { delegateChecked = true; return true; }; const mockLogger = { handle: () => { }, shouldHandle: wrappedShouldHandle, }; const wrapper = new LogMiddlewareWrapper(mockLogger, LogLevels.info, '*'); // When level and namespace match wildcard, should delegate to wrapped logger wrapper.shouldHandle(LogLevels.error, ['test']); assert.ok(delegateChecked, 'Should delegate to wrapped logger when wrapper conditions are met'); }); it('LogMiddlewareWrapper should have public properties', () => { const mockLogger = { handle: () => { }, shouldHandle: () => true, }; const wrapper = new LogMiddlewareWrapper(mockLogger, LogLevels.warn, 'testNamespace'); assert.strictEqual(wrapper.logLevel, LogLevels.warn); assert.strictEqual(wrapper.namespace, 'testNamespace'); }); // Test suite: ConsoleLogger it('ConsoleLogger should be a singleton', () => { const logger1 = new ConsoleLogger(); const logger2 = new ConsoleLogger(); assert.strictEqual(logger1, logger2); }); it('ConsoleLogger should have all log level methods', () => { const logger = new ConsoleLogger(); assert.ok(logger.error); assert.ok(logger.warn); assert.ok(logger.help); assert.ok(logger.data); assert.ok(logger.info); assert.ok(logger.debug); assert.ok(logger.prompt); assert.ok(logger.verbose); assert.ok(logger.input); assert.ok(logger.silly); }); it('ConsoleLogger should track log level independently', () => { const logger = new ConsoleLogger(); const originalLevel = logger.getLevel(); logger.setLevel(LogLevels.warn); assert.strictEqual(logger.getLevel(), LogLevels.warn); // Reset for other tests logger.setLevel(originalLevel); }); it('ConsoleLogger.isEnabled should compare levels correctly', () => { const logger = new ConsoleLogger(); const originalLevel = logger.getLevel(); logger.setLevel(LogLevels.info); // isEnabled returns level >= currentLevel // info (4) >= info (4) = true assert.ok(logger.isEnabled(LogLevels.info)); // error (0) >= info (4) = false assert.ok(!logger.isEnabled(LogLevels.error)); // Reset logger.setLevel(originalLevel); }); it('ConsoleLogger.isEnabled with error level set', () => { const logger = new ConsoleLogger(); const originalLevel = logger.getLevel(); logger.setLevel(LogLevels.error); // error (0) >= error (0) = true assert.ok(logger.isEnabled(LogLevels.error)); // warn (1) >= error (0) = true assert.ok(logger.isEnabled(LogLevels.warn)); // info (4) >= error (0) = true (all levels are >= 0) assert.ok(logger.isEnabled(LogLevels.info)); // Reset logger.setLevel(originalLevel); }); // Test suite: LoggerLogMiddlewareWrapper it('LoggerLogMiddlewareWrapper should wrap all log levels', () => { const mockLogger = { handle: () => { }, shouldHandle: () => true, }; const wrapper = new LoggerLogMiddlewareWrapper(mockLogger); assert.ok(wrapper.error); assert.ok(wrapper.warn); assert.ok(wrapper.help); assert.ok(wrapper.data); assert.ok(wrapper.info); assert.ok(wrapper.debug); assert.ok(wrapper.prompt); assert.ok(wrapper.verbose); assert.ok(wrapper.input); assert.ok(wrapper.silly); }); it('LoggerLogMiddlewareWrapper should create correct log level wrappers', () => { const mockLogger = { handle: () => { }, shouldHandle: () => true, }; const wrapper = new LoggerLogMiddlewareWrapper(mockLogger); assert.strictEqual(wrapper.error.logLevel, LogLevels.error); assert.strictEqual(wrapper.warn.logLevel, LogLevels.warn); assert.strictEqual(wrapper.info.logLevel, LogLevels.info); assert.strictEqual(wrapper.silly.logLevel, LogLevels.silly); }); // Test suite: configureLogging it('configureLogging should update default log level', () => { const originalLevel = logConfig.defaultLevel; try { configureLogging({ defaultLevel: LogLevels.debug }); assert.strictEqual(logConfig.defaultLevel, LogLevels.debug); } finally { logConfig.defaultLevel = originalLevel; } }); it('configureLogging should merge namespace configuration', () => { const originalConfig = JSON.parse(JSON.stringify(logConfig.namespaceConfig)); try { configureLogging({ namespaceConfig: { app: LogLevels.debug, db: LogLevels.silly, }, }); assert.ok(logConfig.namespaceConfig['app']); assert.ok(logConfig.namespaceConfig['db']); } finally { logConfig.namespaceConfig = originalConfig; } }); it('configureLogging should support nested namespace configuration', () => { const originalConfig = JSON.parse(JSON.stringify(logConfig.namespaceConfig)); try { configureLogging({ namespaceConfig: { app: { database: LogLevels.silly, api: LogLevels.debug, }, }, }); assert.ok(logConfig.namespaceConfig['app']); } finally { logConfig.namespaceConfig = originalConfig; } }); it('configureLogging with no arguments should not crash', () => { const originalLevel = logConfig.defaultLevel; const originalConfig = JSON.parse(JSON.stringify(logConfig.namespaceConfig)); try { configureLogging({}); assert.strictEqual(logConfig.defaultLevel, originalLevel); } finally { logConfig.defaultLevel = originalLevel; logConfig.namespaceConfig = originalConfig; } }); // Test suite: LoggerAdapterMiddleware it('LoggerAdapterMiddleware should delegate to correct log level method', () => { const callStack = []; const mockLogger = { error: { handle: () => { callStack.push('error'); }, shouldHandle: () => true, }, warn: { handle: () => { callStack.push('warn'); }, shouldHandle: () => true, }, info: { handle: () => { callStack.push('info'); }, shouldHandle: () => true, }, help: { handle: () => { }, shouldHandle: () => true }, data: { handle: () => { }, shouldHandle: () => true }, debug: { handle: () => { }, shouldHandle: () => true }, prompt: { handle: () => { }, shouldHandle: () => true }, verbose: { handle: () => { }, shouldHandle: () => true }, input: { handle: () => { }, shouldHandle: () => true }, silly: { handle: () => { }, shouldHandle: () => true }, }; const adapter = new LoggerAdapterMiddleware(mockLogger); adapter.handle(LogLevels.error, ['test'], 'error message'); adapter.handle(LogLevels.warn, ['test'], 'warning message'); adapter.handle(LogLevels.info, ['test'], 'info message'); assert.deepStrictEqual(callStack, ['error', 'warn', 'info']); }); it('LoggerAdapterMiddleware should pass all arguments to handler', () => { const capturedArgs = []; const mockLogger = { error: { handle: (level, namespaces, ...args) => { capturedArgs.push(level, namespaces, ...args); }, shouldHandle: () => true, }, warn: { handle: () => { }, shouldHandle: () => true }, help: { handle: () => { }, shouldHandle: () => true }, data: { handle: () => { }, shouldHandle: () => true }, info: { handle: () => { }, shouldHandle: () => true }, debug: { handle: () => { }, shouldHandle: () => true }, prompt: { handle: () => { }, shouldHandle: () => true }, verbose: { handle: () => { }, shouldHandle: () => true }, input: { handle: () => { }, shouldHandle: () => true }, silly: { handle: () => { }, shouldHandle: () => true }, }; const adapter = new LoggerAdapterMiddleware(mockLogger); const testObj = { data: 'test' }; adapter.handle(LogLevels.error, ['app', 'service'], 'message', testObj, 123); assert.strictEqual(capturedArgs[0], LogLevels.error); assert.deepStrictEqual(capturedArgs[1], ['app', 'service']); assert.strictEqual(capturedArgs[2], 'message'); assert.deepStrictEqual(capturedArgs[3], testObj); assert.strictEqual(capturedArgs[4], 123); }); it('LoggerAdapterMiddleware should handle all log levels', () => { const levels = []; const mockLogger = { error: { handle: () => { levels.push(LogLevels.error); }, shouldHandle: () => true, }, warn: { handle: () => { levels.push(LogLevels.warn); }, shouldHandle: () => true, }, help: { handle: () => { levels.push(LogLevels.help); }, shouldHandle: () => true, }, data: { handle: () => { levels.push(LogLevels.data); }, shouldHandle: () => true, }, info: { handle: () => { levels.push(LogLevels.info); }, shouldHandle: () => true, }, debug: { handle: () => { levels.push(LogLevels.debug); }, shouldHandle: () => true, }, prompt: { handle: () => { levels.push(LogLevels.prompt); }, shouldHandle: () => true, }, verbose: { handle: () => { levels.push(LogLevels.verbose); }, shouldHandle: () => true, }, input: { handle: () => { levels.push(LogLevels.input); }, shouldHandle: () => true, }, silly: { handle: () => { levels.push(LogLevels.silly); }, shouldHandle: () => true, }, }; const adapter = new LoggerAdapterMiddleware(mockLogger); Object.values(LogLevels) .filter((v) => typeof v === 'number') .forEach((level) => { adapter.handle(level, ['test']); }); assert.deepStrictEqual(levels.sort((a, b) => a - b), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); }); //# sourceMappingURL=logging.js.map