Cover Handler property accessors, format delegation, emit contract, and close lifecycle. Cover Logger level methods, isEnabledFor caching, manager property assignment, handler management, debug invocation, and makeRecord extra key collision. Cover Manager getLogger hierarchy setup, placeholder fixup, disable level, and loggerClass validation. Cover basicConfig option handling, force flag, mutual exclusion of stream/filename/handlers, and formatter assignment.
181 lines
6.1 KiB
TypeScript
181 lines
6.1 KiB
TypeScript
import {expect, jest, test} from '@jest/globals';
|
|
import { Logger, RootLogger, ROOT } from '../../src/logger';
|
|
import { Handler } from '../../src/handler';
|
|
import { LogRecord } from '../../src/log-record';
|
|
import { Formatter } from '../../src/formatter';
|
|
import { Manager } from '../../src/manager';
|
|
import {
|
|
DEBUG,
|
|
INFO,
|
|
WARNING,
|
|
ERROR,
|
|
CRITICAL,
|
|
NOTSET,
|
|
} from '../../src/log-level';
|
|
import { MyError } from '../../src/helper/error';
|
|
|
|
describe('Logger', () => {
|
|
describe('constructor', () => {
|
|
test('sets scope and default level', () => {
|
|
const logger = new Logger('test');
|
|
expect(logger.scope).toBe('test');
|
|
expect(logger.level).toBe(NOTSET);
|
|
});
|
|
|
|
test('accepts explicit level', () => {
|
|
const logger = new Logger('test', WARNING);
|
|
expect(logger.level).toBe(WARNING);
|
|
});
|
|
});
|
|
|
|
describe('setLevel', () => {
|
|
test('changes the level', () => {
|
|
const logger = new Logger('test');
|
|
logger.setLevel(ERROR);
|
|
expect(logger.level).toBe(ERROR);
|
|
});
|
|
});
|
|
|
|
describe('getEffectiveLevel', () => {
|
|
test('returns own level when set', () => {
|
|
const logger = new Logger('test', WARNING);
|
|
expect(logger.getEffectiveLevel()).toBe(WARNING);
|
|
});
|
|
|
|
test('returns NOTSET when no level set and no parent', () => {
|
|
const logger = new Logger('test');
|
|
expect(logger.getEffectiveLevel()).toBe(NOTSET);
|
|
});
|
|
});
|
|
|
|
describe('isEnabledFor', () => {
|
|
test('returns true when level meets effective level', () => {
|
|
const logger = new Logger('test', DEBUG);
|
|
expect(logger.isEnabledFor(WARNING)).toBe(true);
|
|
expect(logger.isEnabledFor(DEBUG)).toBe(true);
|
|
});
|
|
|
|
test('returns false when level is below effective level', () => {
|
|
const logger = new Logger('test', WARNING);
|
|
expect(logger.isEnabledFor(DEBUG)).toBe(false);
|
|
expect(logger.isEnabledFor(INFO)).toBe(false);
|
|
});
|
|
|
|
test('caches results for repeated calls', () => {
|
|
const logger = new Logger('test', WARNING);
|
|
const first = logger.isEnabledFor(DEBUG);
|
|
const second = logger.isEnabledFor(DEBUG);
|
|
expect(first).toBe(second);
|
|
});
|
|
|
|
test('respects manager disable level', () => {
|
|
const root = new RootLogger(WARNING);
|
|
const manager = new Manager(root);
|
|
const logger = manager.getLogger('test');
|
|
logger.setLevel(DEBUG);
|
|
logger.manager = manager;
|
|
manager.disable = ERROR;
|
|
logger.clear();
|
|
expect(logger.isEnabledFor(DEBUG)).toBe(false);
|
|
expect(logger.isEnabledFor(WARNING)).toBe(false);
|
|
expect(logger.isEnabledFor(CRITICAL)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('manager property', () => {
|
|
test('starts as null', () => {
|
|
const logger = new Logger('test');
|
|
expect(logger.manager).toBeNull();
|
|
});
|
|
|
|
test('can be assigned once', () => {
|
|
const logger = new Logger('test');
|
|
const root = new RootLogger(WARNING);
|
|
const manager = new Manager(root);
|
|
logger.manager = manager;
|
|
expect(logger.manager).toBe(manager);
|
|
});
|
|
|
|
test('throws on second assignment', () => {
|
|
const logger = new Logger('test');
|
|
const root = new RootLogger(WARNING);
|
|
const manager = new Manager(root);
|
|
logger.manager = manager;
|
|
expect(() => { logger.manager = manager }).toThrow('logger can only be assigned to manager once');
|
|
});
|
|
});
|
|
|
|
describe('addHandler / removeHandler', () => {
|
|
test('adds and removes handlers', () => {
|
|
const logger = new Logger('test');
|
|
const handler = new Handler(DEBUG);
|
|
expect(logger.handlers.length).toBe(0);
|
|
logger.addHandler(handler);
|
|
expect(logger.handlers.length).toBe(1);
|
|
logger.removeHandler(handler);
|
|
});
|
|
|
|
test('does not add duplicate handlers', () => {
|
|
const logger = new Logger('test');
|
|
const handler = new Handler(DEBUG);
|
|
logger.addHandler(handler);
|
|
logger.addHandler(handler);
|
|
expect(logger.handlers.length).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('debug', () => {
|
|
test('invokes handler when level is DEBUG', () => {
|
|
const logger = new Logger('test', DEBUG);
|
|
const emitted: LogRecord[] = [];
|
|
|
|
class TestHandler extends Handler {
|
|
emit(record: LogRecord) { emitted.push(record) }
|
|
}
|
|
|
|
logger.addHandler(new TestHandler(DEBUG));
|
|
logger.debug('test message');
|
|
expect(emitted.length).toBe(1);
|
|
expect(emitted[0].scope).toBe('test');
|
|
});
|
|
|
|
test('does not invoke handler when level is above DEBUG', () => {
|
|
const logger = new Logger('test', WARNING);
|
|
const emitted: LogRecord[] = [];
|
|
|
|
class TestHandler extends Handler {
|
|
emit(record: LogRecord) { emitted.push(record) }
|
|
}
|
|
|
|
logger.addHandler(new TestHandler(DEBUG));
|
|
logger.debug('test message');
|
|
expect(emitted.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('makeRecord', () => {
|
|
test('throws KeyError when extra overwrites existing LogRecord key', () => {
|
|
const logger = new Logger('test', DEBUG);
|
|
expect(() => {
|
|
logger.debug('test', {
|
|
excInfo: null,
|
|
extra: { scope: 'override' },
|
|
stackInfo: false,
|
|
stackLevel: 1,
|
|
});
|
|
}).toThrow('attempt to overwrite scope in LogRecord');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('RootLogger', () => {
|
|
test('has scope "root"', () => {
|
|
const root = new RootLogger(WARNING);
|
|
expect(root.scope).toBe('root');
|
|
});
|
|
|
|
test('accepts a level', () => {
|
|
const root = new RootLogger(ERROR);
|
|
expect(root.level).toBe(ERROR);
|
|
});
|
|
});
|