@akala/core
Version:
443 lines • 17.3 kB
JavaScript
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