fmt
This commit is contained in:
@@ -9,7 +9,7 @@ const originalIsTTY = Deno.stdout.isTerminal();
|
||||
|
||||
export function mockConsole() {
|
||||
console.log = (...args) => {
|
||||
capturedLogs.push(args.join(' '));
|
||||
capturedLogs.push(args.join(" "));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ export function restoreMocks() {
|
||||
// Helper to get parsed JSON from first captured log
|
||||
export function getFirstLogAsJSON() {
|
||||
if (capturedLogs.length === 0) {
|
||||
throw new Error('No logs captured');
|
||||
throw new Error("No logs captured");
|
||||
}
|
||||
return JSON.parse(capturedLogs[0]);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import { assertEquals, assert } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import { assert, assertEquals } from "@std/assert";
|
||||
import Logger from "../lib/logger.ts";
|
||||
|
||||
Deno.test("Logger callerLevel - Caller Information Filtering - should include caller info for error when callerLevel is warn", () => {
|
||||
const logger = new Logger({ callerLevel: 'warn' });
|
||||
const logger = new Logger({ callerLevel: "warn" });
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
logger.error('test message');
|
||||
logger.error("test message");
|
||||
|
||||
// Parse JSON output and check for caller info
|
||||
const logEntry = JSON.parse(capturedOutput);
|
||||
assert(
|
||||
logEntry.callerFile,
|
||||
'Should include callerFile for error level'
|
||||
"Should include callerFile for error level",
|
||||
);
|
||||
assert(
|
||||
typeof logEntry.callerLine === 'number',
|
||||
'Should include callerLine for error level'
|
||||
typeof logEntry.callerLine === "number",
|
||||
"Should include callerLine for error level",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -30,27 +30,27 @@ Deno.test("Logger callerLevel - Caller Information Filtering - should include ca
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Caller Information Filtering - should include caller info for warn when callerLevel is warn", () => {
|
||||
const logger = new Logger({ callerLevel: 'warn' });
|
||||
const logger = new Logger({ callerLevel: "warn" });
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
logger.warn('test message');
|
||||
logger.warn("test message");
|
||||
|
||||
// Parse JSON output and check for caller info
|
||||
const logEntry = JSON.parse(capturedOutput);
|
||||
assert(
|
||||
logEntry.callerFile,
|
||||
'Should include callerFile for warn level'
|
||||
"Should include callerFile for warn level",
|
||||
);
|
||||
assert(
|
||||
typeof logEntry.callerLine === 'number',
|
||||
'Should include callerLine for warn level'
|
||||
typeof logEntry.callerLine === "number",
|
||||
"Should include callerLine for warn level",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -58,29 +58,29 @@ Deno.test("Logger callerLevel - Caller Information Filtering - should include ca
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Caller Information Filtering - should NOT include caller info for info when callerLevel is warn", () => {
|
||||
const logger = new Logger({ callerLevel: 'warn' });
|
||||
const logger = new Logger({ callerLevel: "warn" });
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
// Parse JSON output and check for absence of caller info
|
||||
const logEntry = JSON.parse(capturedOutput);
|
||||
assertEquals(
|
||||
logEntry.callerFile,
|
||||
undefined,
|
||||
'Should NOT include callerFile for info level'
|
||||
"Should NOT include callerFile for info level",
|
||||
);
|
||||
assertEquals(
|
||||
logEntry.callerLine,
|
||||
undefined,
|
||||
'Should NOT include callerLine for info level'
|
||||
"Should NOT include callerLine for info level",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -88,29 +88,29 @@ Deno.test("Logger callerLevel - Caller Information Filtering - should NOT includ
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Caller Information Filtering - should NOT include caller info for debug when callerLevel is warn", () => {
|
||||
const logger = new Logger({ callerLevel: 'warn', level: 'debug' }); // Set level to debug to ensure debug messages are logged
|
||||
const logger = new Logger({ callerLevel: "warn", level: "debug" }); // Set level to debug to ensure debug messages are logged
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
logger.debug('test message');
|
||||
logger.debug("test message");
|
||||
|
||||
// Parse JSON output and check for absence of caller info
|
||||
const logEntry = JSON.parse(capturedOutput);
|
||||
assertEquals(
|
||||
logEntry.callerFile,
|
||||
undefined,
|
||||
'Should NOT include callerFile for debug level'
|
||||
"Should NOT include callerFile for debug level",
|
||||
);
|
||||
assertEquals(
|
||||
logEntry.callerLine,
|
||||
undefined,
|
||||
'Should NOT include callerLine for debug level'
|
||||
"Should NOT include callerLine for debug level",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -118,29 +118,29 @@ Deno.test("Logger callerLevel - Caller Information Filtering - should NOT includ
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Caller Information Filtering - should include caller info for all levels when callerLevel is debug", () => {
|
||||
const logger = new Logger({ callerLevel: 'debug', level: 'debug' });
|
||||
const logger = new Logger({ callerLevel: "debug", level: "debug" });
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
// Test each level
|
||||
const levels = ['error', 'warn', 'info', 'debug'];
|
||||
const levels = ["error", "warn", "info", "debug"];
|
||||
for (const level of levels) {
|
||||
logger[level]('test message');
|
||||
logger[level]("test message");
|
||||
|
||||
const logEntry = JSON.parse(capturedOutput);
|
||||
assert(
|
||||
logEntry.callerFile,
|
||||
`Should include callerFile for ${level} level`
|
||||
`Should include callerFile for ${level} level`,
|
||||
);
|
||||
assert(
|
||||
typeof logEntry.callerLine === 'number',
|
||||
`Should include callerLine for ${level} level`
|
||||
typeof logEntry.callerLine === "number",
|
||||
`Should include callerLine for ${level} level`,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -149,31 +149,31 @@ Deno.test("Logger callerLevel - Caller Information Filtering - should include ca
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Caller Information Filtering - should NOT include caller info for any level when callerLevel is silent", () => {
|
||||
const logger = new Logger({ callerLevel: 'silent', level: 'debug' });
|
||||
const logger = new Logger({ callerLevel: "silent", level: "debug" });
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
// Test each level
|
||||
const levels = ['error', 'warn', 'info', 'debug'];
|
||||
const levels = ["error", "warn", "info", "debug"];
|
||||
for (const level of levels) {
|
||||
logger[level]('test message');
|
||||
logger[level]("test message");
|
||||
|
||||
const logEntry = JSON.parse(capturedOutput);
|
||||
assertEquals(
|
||||
logEntry.callerFile,
|
||||
undefined,
|
||||
`Should NOT include callerFile for ${level} level`
|
||||
`Should NOT include callerFile for ${level} level`,
|
||||
);
|
||||
assertEquals(
|
||||
logEntry.callerLine,
|
||||
undefined,
|
||||
`Should NOT include callerLine for ${level} level`
|
||||
`Should NOT include callerLine for ${level} level`,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -182,33 +182,33 @@ Deno.test("Logger callerLevel - Caller Information Filtering - should NOT includ
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Simple Formatter with callerLevel - should format correctly without caller info when excluded", () => {
|
||||
const logger = new Logger({ format: 'simple', callerLevel: 'error' });
|
||||
const logger = new Logger({ format: "simple", callerLevel: "error" });
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
// Should not contain caller info pattern
|
||||
assert(
|
||||
!capturedOutput.includes('unknown'),
|
||||
'Should not include caller placeholder'
|
||||
!capturedOutput.includes("unknown"),
|
||||
"Should not include caller placeholder",
|
||||
);
|
||||
assert(
|
||||
!capturedOutput.includes('.js:'),
|
||||
'Should not include file:line pattern'
|
||||
!capturedOutput.includes(".js:"),
|
||||
"Should not include file:line pattern",
|
||||
);
|
||||
|
||||
// Should still contain other parts
|
||||
assert(capturedOutput.includes('INFO'), 'Should include log level');
|
||||
assert(capturedOutput.includes("INFO"), "Should include log level");
|
||||
assert(
|
||||
capturedOutput.includes('test message'),
|
||||
'Should include message'
|
||||
capturedOutput.includes("test message"),
|
||||
"Should include message",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -216,27 +216,27 @@ Deno.test("Logger callerLevel - Simple Formatter with callerLevel - should forma
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Simple Formatter with callerLevel - should format correctly with caller info when included", () => {
|
||||
const logger = new Logger({ format: 'simple', callerLevel: 'info' });
|
||||
const logger = new Logger({ format: "simple", callerLevel: "info" });
|
||||
|
||||
// Mock console.log to capture output
|
||||
const originalLog = console.log;
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
// Should contain caller info pattern
|
||||
assert(
|
||||
capturedOutput.includes('.js:'),
|
||||
'Should include file:line pattern'
|
||||
capturedOutput.includes(".js:"),
|
||||
"Should include file:line pattern",
|
||||
);
|
||||
assert(capturedOutput.includes('INFO'), 'Should include log level');
|
||||
assert(capturedOutput.includes("INFO"), "Should include log level");
|
||||
assert(
|
||||
capturedOutput.includes('test message'),
|
||||
'Should include message'
|
||||
capturedOutput.includes("test message"),
|
||||
"Should include message",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -244,7 +244,7 @@ Deno.test("Logger callerLevel - Simple Formatter with callerLevel - should forma
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Performance Considerations - should not call getCallerInfo when caller info is not needed", () => {
|
||||
const logger = new Logger({ callerLevel: 'error' });
|
||||
const logger = new Logger({ callerLevel: "error" });
|
||||
|
||||
// Spy on getCallerInfo method
|
||||
let getCallerInfoCalled = false;
|
||||
@@ -259,11 +259,11 @@ Deno.test("Logger callerLevel - Performance Considerations - should not call get
|
||||
console.log = () => {};
|
||||
|
||||
try {
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
assertEquals(
|
||||
getCallerInfoCalled,
|
||||
false,
|
||||
'getCallerInfo should not be called for info level when callerLevel is error'
|
||||
"getCallerInfo should not be called for info level when callerLevel is error",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -271,7 +271,7 @@ Deno.test("Logger callerLevel - Performance Considerations - should not call get
|
||||
});
|
||||
|
||||
Deno.test("Logger callerLevel - Performance Considerations - should call getCallerInfo when caller info is needed", () => {
|
||||
const logger = new Logger({ callerLevel: 'warn' });
|
||||
const logger = new Logger({ callerLevel: "warn" });
|
||||
|
||||
// Spy on getCallerInfo method
|
||||
let getCallerInfoCalled = false;
|
||||
@@ -286,13 +286,13 @@ Deno.test("Logger callerLevel - Performance Considerations - should call getCall
|
||||
console.log = () => {};
|
||||
|
||||
try {
|
||||
logger.error('test message');
|
||||
logger.error("test message");
|
||||
assertEquals(
|
||||
getCallerInfoCalled,
|
||||
true,
|
||||
'getCallerInfo should be called for error level when callerLevel is warn'
|
||||
"getCallerInfo should be called for error level when callerLevel is warn",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,74 +1,110 @@
|
||||
import { assertEquals, assertThrows } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import Logger from "../lib/logger.ts";
|
||||
|
||||
Deno.test("Logger Constructor - should throw error for invalid log level", () => {
|
||||
assertThrows(() => {
|
||||
new Logger({ level: 'invalid' });
|
||||
}, Error, "Invalid log level: invalid. Valid levels are: silent, error, warn, info, debug");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ level: "invalid" });
|
||||
},
|
||||
Error,
|
||||
"Invalid log level: invalid. Valid levels are: silent, error, warn, info, debug",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should throw error for invalid format", () => {
|
||||
assertThrows(() => {
|
||||
new Logger({ format: 'invalid' });
|
||||
}, Error, "Invalid format: invalid. Valid formats are: json, simple");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ format: "invalid" });
|
||||
},
|
||||
Error,
|
||||
"Invalid format: invalid. Valid formats are: json, simple",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should throw error for invalid time option", () => {
|
||||
assertThrows(() => {
|
||||
new Logger({ time: 'invalid' });
|
||||
}, Error, "Invalid time: invalid. Valid times are: long, short");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ time: "invalid" });
|
||||
},
|
||||
Error,
|
||||
"Invalid time: invalid. Valid times are: long, short",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should throw error for invalid callerLevel", () => {
|
||||
assertThrows(() => {
|
||||
new Logger({ callerLevel: 'invalid' });
|
||||
}, Error, "Invalid callerLevel: invalid. Valid levels are: silent, error, warn, info, debug");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ callerLevel: "invalid" });
|
||||
},
|
||||
Error,
|
||||
"Invalid callerLevel: invalid. Valid levels are: silent, error, warn, info, debug",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should throw error for non-object colours", () => {
|
||||
assertThrows(() => {
|
||||
new Logger({ colours: 'not an object' });
|
||||
}, Error, "colours option must be an object");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ colours: "not an object" });
|
||||
},
|
||||
Error,
|
||||
"colours option must be an object",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should throw error for non-object levels", () => {
|
||||
assertThrows(() => {
|
||||
new Logger({ levels: 'not an object' });
|
||||
}, Error, "levels option must be an object");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ levels: "not an object" });
|
||||
},
|
||||
Error,
|
||||
"levels option must be an object",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should throw error for invalid level values", () => {
|
||||
assertThrows(() => {
|
||||
new Logger({ levels: { error: -1 } });
|
||||
}, Error, "Level value for 'error' must be a non-negative integer");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ levels: { error: -1 } });
|
||||
},
|
||||
Error,
|
||||
"Level value for 'error' must be a non-negative integer",
|
||||
);
|
||||
|
||||
assertThrows(() => {
|
||||
new Logger({ levels: { error: 'not a number' } });
|
||||
}, Error, "Level value for 'error' must be a non-negative integer");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ levels: { error: "not a number" } });
|
||||
},
|
||||
Error,
|
||||
"Level value for 'error' must be a non-negative integer",
|
||||
);
|
||||
|
||||
assertThrows(() => {
|
||||
new Logger({ levels: { error: 1.5 } });
|
||||
}, Error, "Level value for 'error' must be a non-negative integer");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ levels: { error: 1.5 } });
|
||||
},
|
||||
Error,
|
||||
"Level value for 'error' must be a non-negative integer",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should accept valid options without throwing", () => {
|
||||
// This should not throw
|
||||
new Logger({
|
||||
level: 'debug',
|
||||
format: 'simple',
|
||||
time: 'long',
|
||||
callerLevel: 'error',
|
||||
colours: { error: '\x1b[31m' },
|
||||
level: "debug",
|
||||
format: "simple",
|
||||
time: "long",
|
||||
callerLevel: "error",
|
||||
colours: { error: "\x1b[31m" },
|
||||
levels: { custom: 4 },
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should instantiate with default options", () => {
|
||||
const logger = new Logger();
|
||||
assertEquals(logger.options.level, 'info');
|
||||
assertEquals(logger.options.format, 'json');
|
||||
assertEquals(logger.options.time, 'short');
|
||||
assertEquals(logger.options.callerLevel, 'warn');
|
||||
assertEquals(logger.options.level, "info");
|
||||
assertEquals(logger.options.format, "json");
|
||||
assertEquals(logger.options.time, "short");
|
||||
assertEquals(logger.options.callerLevel, "warn");
|
||||
assertEquals(logger.options.levels, {
|
||||
silent: -1,
|
||||
error: 0,
|
||||
@@ -80,49 +116,49 @@ Deno.test("Logger Constructor - should instantiate with default options", () =>
|
||||
|
||||
Deno.test("Logger Constructor - should instantiate with custom options", () => {
|
||||
const logger = new Logger({
|
||||
level: 'debug',
|
||||
format: 'simple',
|
||||
time: 'long',
|
||||
callerLevel: 'error',
|
||||
level: "debug",
|
||||
format: "simple",
|
||||
time: "long",
|
||||
callerLevel: "error",
|
||||
});
|
||||
assertEquals(logger.options.level, 'debug');
|
||||
assertEquals(logger.options.format, 'simple');
|
||||
assertEquals(logger.options.time, 'long');
|
||||
assertEquals(logger.options.callerLevel, 'error');
|
||||
assertEquals(logger.options.level, "debug");
|
||||
assertEquals(logger.options.format, "simple");
|
||||
assertEquals(logger.options.time, "long");
|
||||
assertEquals(logger.options.callerLevel, "error");
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should merge options correctly", () => {
|
||||
const customOptions = {
|
||||
level: 'debug',
|
||||
format: 'simple',
|
||||
time: 'long',
|
||||
level: "debug",
|
||||
format: "simple",
|
||||
time: "long",
|
||||
colours: {
|
||||
error: '\x1b[31m', // different red
|
||||
error: "\x1b[31m", // different red
|
||||
},
|
||||
};
|
||||
|
||||
const logger = new Logger(customOptions);
|
||||
|
||||
assertEquals(logger.options.level, 'debug');
|
||||
assertEquals(logger.options.format, 'simple');
|
||||
assertEquals(logger.options.time, 'long');
|
||||
assertEquals(logger.options.colours.error, '\x1b[31m');
|
||||
assertEquals(logger.options.level, "debug");
|
||||
assertEquals(logger.options.format, "simple");
|
||||
assertEquals(logger.options.time, "long");
|
||||
assertEquals(logger.options.colours.error, "\x1b[31m");
|
||||
// Should still have other default colors
|
||||
assertEquals(logger.options.colours.warn, '\x1b[33m');
|
||||
assertEquals(logger.options.colours.warn, "\x1b[33m");
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should have all log level methods", () => {
|
||||
const logger = new Logger();
|
||||
assertEquals(typeof logger.error, 'function');
|
||||
assertEquals(typeof logger.warn, 'function');
|
||||
assertEquals(typeof logger.info, 'function');
|
||||
assertEquals(typeof logger.debug, 'function');
|
||||
assertEquals(typeof logger.error, "function");
|
||||
assertEquals(typeof logger.warn, "function");
|
||||
assertEquals(typeof logger.info, "function");
|
||||
assertEquals(typeof logger.debug, "function");
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should have level management methods", () => {
|
||||
const logger = new Logger();
|
||||
assertEquals(typeof logger.level, 'function');
|
||||
assertEquals(typeof logger.setLevel, 'function');
|
||||
assertEquals(typeof logger.level, "function");
|
||||
assertEquals(typeof logger.setLevel, "function");
|
||||
});
|
||||
|
||||
Deno.test("Logger Constructor - should detect TTY correctly", () => {
|
||||
@@ -146,13 +182,13 @@ Deno.test("Logger Constructor - should work with all existing constructor patter
|
||||
new Logger();
|
||||
|
||||
// Partial options - should not throw
|
||||
new Logger({ level: 'debug' });
|
||||
new Logger({ level: "debug" });
|
||||
|
||||
// Full options (without time) - should not throw
|
||||
new Logger({
|
||||
level: 'warn',
|
||||
format: 'simple',
|
||||
colours: { error: '\x1b[31m' },
|
||||
level: "warn",
|
||||
format: "simple",
|
||||
colours: { error: "\x1b[31m" },
|
||||
levels: { custom: 5 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { assertEquals, assert } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import { assert, assertEquals } from "@std/assert";
|
||||
import Logger from "../lib/logger.ts";
|
||||
import {
|
||||
setupMocks,
|
||||
getCapturedLogs,
|
||||
clearCapturedLogs,
|
||||
} from './helpers/logger-test-helpers.js';
|
||||
getCapturedLogs,
|
||||
setupMocks,
|
||||
} from "./helpers/logger-test-helpers.js";
|
||||
|
||||
// Setup and teardown for all tests
|
||||
setupMocks();
|
||||
|
||||
Deno.test("Logger Internal Error Handling - Formatter Error Handling - should fall back to JSON formatter when custom formatter throws", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const logger = new Logger({ format: "simple" });
|
||||
|
||||
// Replace the simple formatter with one that throws
|
||||
logger.formatters.simple = function () {
|
||||
throw new Error('Custom formatter error');
|
||||
throw new Error("Custom formatter error");
|
||||
};
|
||||
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
// Should still produce output using JSON formatter fallback
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
@@ -26,24 +26,24 @@ Deno.test("Logger Internal Error Handling - Formatter Error Handling - should fa
|
||||
// Should be valid JSON (fallback to JSON formatter)
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
const parsed = JSON.parse(logOutput);
|
||||
assertEquals(parsed.msg, 'test message');
|
||||
assertEquals(parsed.msg, "test message");
|
||||
assert(
|
||||
parsed.formatterError.includes(
|
||||
'Formatter failed: Custom formatter error'
|
||||
)
|
||||
"Formatter failed: Custom formatter error",
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Internal Error Handling - Formatter Error Handling - should not crash when formatter returns non-string", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const logger = new Logger({ format: "simple" });
|
||||
|
||||
// Replace formatter with one that returns an object instead of string
|
||||
logger.formatters.simple = function () {
|
||||
return { notAString: true };
|
||||
};
|
||||
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
// Should still produce output (fallback should handle this)
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
@@ -51,25 +51,25 @@ Deno.test("Logger Internal Error Handling - Formatter Error Handling - should no
|
||||
// Should be valid JSON from fallback
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
const parsed = JSON.parse(logOutput);
|
||||
assertEquals(parsed.msg, 'test message');
|
||||
assertEquals(parsed.msg, "test message");
|
||||
});
|
||||
|
||||
Deno.test("Logger Internal Error Handling - Formatter Error Handling - should preserve original formatters after error", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const logger = new Logger({ format: "simple" });
|
||||
|
||||
// Temporarily break the formatter
|
||||
const originalSimple = logger.formatters.simple;
|
||||
logger.formatters.simple = function () {
|
||||
throw new Error('Temporary error');
|
||||
throw new Error("Temporary error");
|
||||
};
|
||||
|
||||
logger.info('first message');
|
||||
logger.info("first message");
|
||||
|
||||
// Restore the formatter
|
||||
logger.formatters.simple = originalSimple;
|
||||
|
||||
logger.info('second message');
|
||||
logger.info("second message");
|
||||
|
||||
// First message should have used fallback, second should work normally
|
||||
assertEquals(getCapturedLogs().length, 2);
|
||||
@@ -78,17 +78,17 @@ Deno.test("Logger Internal Error Handling - Formatter Error Handling - should pr
|
||||
JSON.parse(getCapturedLogs()[0]); // This should not throw
|
||||
|
||||
// Second log should be simple format
|
||||
assert(getCapturedLogs()[1].includes('[INFO ]'));
|
||||
assert(getCapturedLogs()[1].includes('second message'));
|
||||
assert(getCapturedLogs()[1].includes("[INFO ]"));
|
||||
assert(getCapturedLogs()[1].includes("second message"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Internal Error Handling - Formatter Error Handling - should handle repeated formatter failures without memory leaks", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const logger = new Logger({ format: "simple" });
|
||||
|
||||
// Break the formatter
|
||||
logger.formatters.simple = function () {
|
||||
throw new Error('Always fails');
|
||||
throw new Error("Always fails");
|
||||
};
|
||||
|
||||
// Log many times
|
||||
@@ -103,4 +103,4 @@ Deno.test("Logger Internal Error Handling - Formatter Error Handling - should ha
|
||||
getCapturedLogs().forEach((log) => {
|
||||
JSON.parse(log); // This should not throw
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,89 +1,89 @@
|
||||
import { assertEquals, assertThrows, assert } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import { assert, assertEquals, assertThrows } from "@std/assert";
|
||||
import Logger from "../lib/logger.ts";
|
||||
import {
|
||||
setupMocks,
|
||||
getCapturedLogs,
|
||||
clearCapturedErrors,
|
||||
clearCapturedLogs,
|
||||
getCapturedErrors,
|
||||
clearCapturedErrors,
|
||||
} from './helpers/logger-test-helpers.js';
|
||||
getCapturedLogs,
|
||||
setupMocks,
|
||||
} from "./helpers/logger-test-helpers.js";
|
||||
|
||||
// Setup and teardown for all tests
|
||||
setupMocks();
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - JSON Formatter Error Handling - should handle circular references in log data", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Create circular reference
|
||||
const obj = { name: 'test' };
|
||||
const obj = { name: "test" };
|
||||
obj.self = obj;
|
||||
|
||||
logger.info('Message with circular ref: %j', obj);
|
||||
logger.info("Message with circular ref: %j", obj);
|
||||
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should be valid JSON despite circular reference
|
||||
const parsed = JSON.parse(logOutput);
|
||||
assertEquals(parsed.level, 'info');
|
||||
assertEquals(parsed.level, "info");
|
||||
// Check for either jsonError or that the message was logged successfully
|
||||
assert(
|
||||
parsed.jsonError?.includes('JSON stringify failed') ||
|
||||
parsed.msg.includes('Message with circular ref')
|
||||
parsed.jsonError?.includes("JSON stringify failed") ||
|
||||
parsed.msg.includes("Message with circular ref"),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - JSON Formatter Error Handling - should handle objects with non-serializable properties", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Create object with function (non-serializable)
|
||||
const objWithFunction = {
|
||||
name: 'test',
|
||||
name: "test",
|
||||
func: function () {
|
||||
return 'hello';
|
||||
return "hello";
|
||||
},
|
||||
symbol: Symbol('test'),
|
||||
symbol: Symbol("test"),
|
||||
undefined: undefined,
|
||||
};
|
||||
|
||||
logger.info('Object: %j', objWithFunction);
|
||||
logger.info("Object: %j", objWithFunction);
|
||||
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should produce valid JSON
|
||||
const parsed = JSON.parse(logOutput);
|
||||
assertEquals(parsed.level, 'info');
|
||||
assertEquals(parsed.level, "info");
|
||||
// Should have the message in some form
|
||||
assert(parsed.msg.includes('Object:'));
|
||||
assert(parsed.msg.includes("Object:"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - JSON Formatter Error Handling - should handle when JSON formatter itself is broken", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Break the JSON formatter
|
||||
logger.formatters.json = function () {
|
||||
throw new Error('JSON formatter is broken');
|
||||
throw new Error("JSON formatter is broken");
|
||||
};
|
||||
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
// Should still produce some output (last resort fallback)
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should contain the message even if not perfectly formatted
|
||||
assert(logOutput.includes('test message'));
|
||||
assert(logOutput.includes("test message"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - Caller Detection Error Handling - should handle stack manipulation errors", () => {
|
||||
clearCapturedLogs();
|
||||
clearCapturedErrors();
|
||||
|
||||
const logger = new Logger({ format: 'json', callerLevel: 'info' });
|
||||
const logger = new Logger({ format: "json", callerLevel: "info" });
|
||||
|
||||
// Override getCallerInfo to simulate an error
|
||||
const originalGetCallerInfo = logger.getCallerInfo;
|
||||
@@ -91,26 +91,26 @@ Deno.test("Logger Additional Fallback Tests - Caller Detection Error Handling -
|
||||
this.callerErrorCount++;
|
||||
if (this.callerErrorCount <= this.maxCallerErrors) {
|
||||
console.error(
|
||||
'Error retrieving caller info:',
|
||||
new Error('Simulated caller error')
|
||||
"Error retrieving caller info:",
|
||||
new Error("Simulated caller error"),
|
||||
);
|
||||
if (this.callerErrorCount === this.maxCallerErrors) {
|
||||
console.error(
|
||||
`Caller detection failed ${this.maxCallerErrors} times. Suppressing further caller error messages.`
|
||||
`Caller detection failed ${this.maxCallerErrors} times. Suppressing further caller error messages.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return { callerFile: 'unknown', callerLine: 0 };
|
||||
return { callerFile: "unknown", callerLine: 0 };
|
||||
};
|
||||
|
||||
try {
|
||||
logger.info('test with simulated caller error');
|
||||
logger.info("test with simulated caller error");
|
||||
|
||||
// Should still log the message
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
const parsed = JSON.parse(getCapturedLogs()[0]);
|
||||
assertEquals(parsed.msg, 'test with simulated caller error');
|
||||
assertEquals(parsed.callerFile, 'unknown');
|
||||
assertEquals(parsed.msg, "test with simulated caller error");
|
||||
assertEquals(parsed.callerFile, "unknown");
|
||||
assertEquals(parsed.callerLine, 0);
|
||||
|
||||
// Should have logged an error about caller detection
|
||||
@@ -125,7 +125,7 @@ Deno.test("Logger Additional Fallback Tests - Caller Detection Error Handling -
|
||||
clearCapturedLogs();
|
||||
clearCapturedErrors();
|
||||
|
||||
const logger = new Logger({ format: 'json', callerLevel: 'info' });
|
||||
const logger = new Logger({ format: "json", callerLevel: "info" });
|
||||
|
||||
// Override getCallerInfo to always simulate errors
|
||||
const originalGetCallerInfo = logger.getCallerInfo;
|
||||
@@ -133,16 +133,16 @@ Deno.test("Logger Additional Fallback Tests - Caller Detection Error Handling -
|
||||
this.callerErrorCount++;
|
||||
if (this.callerErrorCount <= this.maxCallerErrors) {
|
||||
console.error(
|
||||
'Error retrieving caller info:',
|
||||
new Error('Always fails')
|
||||
"Error retrieving caller info:",
|
||||
new Error("Always fails"),
|
||||
);
|
||||
if (this.callerErrorCount === this.maxCallerErrors) {
|
||||
console.error(
|
||||
`Caller detection failed ${this.maxCallerErrors} times. Suppressing further caller error messages.`
|
||||
`Caller detection failed ${this.maxCallerErrors} times. Suppressing further caller error messages.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return { callerFile: 'unknown', callerLine: 0 };
|
||||
return { callerFile: "unknown", callerLine: 0 };
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -163,8 +163,8 @@ Deno.test("Logger Additional Fallback Tests - Caller Detection Error Handling -
|
||||
const suppressionFound = errorLogs.some((errorArgs) =>
|
||||
errorArgs.some(
|
||||
(arg) =>
|
||||
typeof arg === 'string' &&
|
||||
arg.includes('Suppressing further caller error messages')
|
||||
typeof arg === "string" &&
|
||||
arg.includes("Suppressing further caller error messages"),
|
||||
)
|
||||
);
|
||||
assert(suppressionFound);
|
||||
@@ -178,50 +178,50 @@ Deno.test("Logger Additional Fallback Tests - Caller Detection Error Handling -
|
||||
clearCapturedLogs();
|
||||
clearCapturedErrors();
|
||||
|
||||
const logger = new Logger({ format: 'json', callerLevel: 'info' });
|
||||
const logger = new Logger({ format: "json", callerLevel: "info" });
|
||||
|
||||
// Override getCallerInfo to simulate different phases
|
||||
const originalGetCallerInfo = logger.getCallerInfo;
|
||||
let phase = 'error1';
|
||||
let phase = "error1";
|
||||
|
||||
logger.getCallerInfo = function () {
|
||||
if (phase === 'error1') {
|
||||
if (phase === "error1") {
|
||||
this.callerErrorCount++;
|
||||
if (this.callerErrorCount <= this.maxCallerErrors) {
|
||||
console.error(
|
||||
'Error retrieving caller info:',
|
||||
new Error('Phase 1 error')
|
||||
"Error retrieving caller info:",
|
||||
new Error("Phase 1 error"),
|
||||
);
|
||||
}
|
||||
return { callerFile: 'unknown', callerLine: 0 };
|
||||
} else if (phase === 'working') {
|
||||
return { callerFile: "unknown", callerLine: 0 };
|
||||
} else if (phase === "working") {
|
||||
// Reset error count on successful call
|
||||
this.callerErrorCount = 0;
|
||||
return originalGetCallerInfo.call(this);
|
||||
} else if (phase === 'error2') {
|
||||
} else if (phase === "error2") {
|
||||
this.callerErrorCount++;
|
||||
if (this.callerErrorCount <= this.maxCallerErrors) {
|
||||
console.error(
|
||||
'Error retrieving caller info:',
|
||||
new Error('Phase 2 error')
|
||||
"Error retrieving caller info:",
|
||||
new Error("Phase 2 error"),
|
||||
);
|
||||
}
|
||||
return { callerFile: 'unknown', callerLine: 0 };
|
||||
return { callerFile: "unknown", callerLine: 0 };
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
// Cause some errors
|
||||
logger.info('test 1');
|
||||
logger.info('test 2');
|
||||
logger.info("test 1");
|
||||
logger.info("test 2");
|
||||
|
||||
// Switch to working mode
|
||||
phase = 'working';
|
||||
logger.info('test 3');
|
||||
phase = "working";
|
||||
logger.info("test 3");
|
||||
|
||||
// Break it again
|
||||
phase = 'error2';
|
||||
logger.info('test 4');
|
||||
phase = "error2";
|
||||
logger.info("test 4");
|
||||
|
||||
const errorLogs = getCapturedErrors();
|
||||
// Should have errors from both phases
|
||||
@@ -234,20 +234,24 @@ Deno.test("Logger Additional Fallback Tests - Caller Detection Error Handling -
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - Extreme Error Conditions - should handle when console.log itself throws", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Break console.log
|
||||
const originalLog = console.log;
|
||||
console.log = function () {
|
||||
throw new Error('Console is broken');
|
||||
throw new Error("Console is broken");
|
||||
};
|
||||
|
||||
try {
|
||||
// This should not crash the process, but the error will bubble up
|
||||
// since there's no try-catch around console.log in the logger
|
||||
assertThrows(() => {
|
||||
logger.info('test message');
|
||||
}, Error, "Console is broken");
|
||||
assertThrows(
|
||||
() => {
|
||||
logger.info("test message");
|
||||
},
|
||||
Error,
|
||||
"Console is broken",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
@@ -255,20 +259,20 @@ Deno.test("Logger Additional Fallback Tests - Extreme Error Conditions - should
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - Extreme Error Conditions - should handle when util.format has issues with complex objects", () => {
|
||||
setupMocks();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Create an object that will cause issues with string conversion
|
||||
const problematicObject = {
|
||||
toString: function () {
|
||||
throw new Error('toString failed');
|
||||
throw new Error("toString failed");
|
||||
},
|
||||
valueOf: function () {
|
||||
throw new Error('valueOf failed');
|
||||
throw new Error("valueOf failed");
|
||||
},
|
||||
};
|
||||
|
||||
// The logger should handle this gracefully and not throw
|
||||
logger.info('Message: %s', problematicObject);
|
||||
logger.info("Message: %s", problematicObject);
|
||||
|
||||
const logs = getCapturedLogs();
|
||||
assertEquals(logs.length, 1);
|
||||
@@ -276,15 +280,14 @@ Deno.test("Logger Additional Fallback Tests - Extreme Error Conditions - should
|
||||
const output = JSON.parse(logs[0]);
|
||||
// The logger should handle the problematic object gracefully
|
||||
// Either by showing [object Object] or the actual object structure
|
||||
assertEquals(typeof output.msg, 'string');
|
||||
assertEquals(output.msg.startsWith('Message: '), true);
|
||||
|
||||
assertEquals(typeof output.msg, "string");
|
||||
assertEquals(output.msg.startsWith("Message: "), true);
|
||||
});
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - Extreme Error Conditions - should handle when hostname fails", () => {
|
||||
setupMocks();
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Mock hostname retrieval to throw (this would need to be mocked at the source)
|
||||
// Since we can't directly mock os.hostname in Deno, this test shows the concept
|
||||
@@ -292,9 +295,8 @@ Deno.test("Logger Additional Fallback Tests - Extreme Error Conditions - should
|
||||
|
||||
// For Deno, we could mock the hostname call if it were extracted to a mockable function
|
||||
// For now, this is more of a documentation test
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
|
||||
});
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - Fallback Chain Testing - should handle formatter failures gracefully", () => {
|
||||
@@ -302,11 +304,11 @@ Deno.test("Logger Additional Fallback Tests - Fallback Chain Testing - should ha
|
||||
clearCapturedLogs();
|
||||
clearCapturedErrors();
|
||||
|
||||
const logger = new Logger({ format: 'simple', callerLevel: 'info' });
|
||||
const logger = new Logger({ format: "simple", callerLevel: "info" });
|
||||
|
||||
// Break the simple formatter
|
||||
logger.formatters.simple = function () {
|
||||
throw new Error('Simple formatter broken');
|
||||
throw new Error("Simple formatter broken");
|
||||
};
|
||||
|
||||
// Also simulate caller detection failure
|
||||
@@ -315,16 +317,16 @@ Deno.test("Logger Additional Fallback Tests - Fallback Chain Testing - should ha
|
||||
this.callerErrorCount++;
|
||||
if (this.callerErrorCount <= this.maxCallerErrors) {
|
||||
console.error(
|
||||
'Error retrieving caller info:',
|
||||
new Error('Caller detection failed')
|
||||
"Error retrieving caller info:",
|
||||
new Error("Caller detection failed"),
|
||||
);
|
||||
}
|
||||
return { callerFile: 'unknown', callerLine: 0 };
|
||||
return { callerFile: "unknown", callerLine: 0 };
|
||||
};
|
||||
|
||||
try {
|
||||
// Should still produce some output despite multiple failures
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
// Should produce some kind of output (fallback to JSON formatter)
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
@@ -332,13 +334,13 @@ Deno.test("Logger Additional Fallback Tests - Fallback Chain Testing - should ha
|
||||
|
||||
// Should be valid JSON (fallback formatter)
|
||||
const parsed = JSON.parse(output);
|
||||
assertEquals(parsed.msg, 'test message');
|
||||
assert(parsed.formatterError.includes('Simple formatter broken'));
|
||||
assertEquals(parsed.callerFile, 'unknown');
|
||||
assertEquals(parsed.msg, "test message");
|
||||
assert(parsed.formatterError.includes("Simple formatter broken"));
|
||||
assertEquals(parsed.callerFile, "unknown");
|
||||
} finally {
|
||||
logger.getCallerInfo = originalGetCallerInfo;
|
||||
logger.callerErrorCount = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger Additional Fallback Tests - Resource Cleanup - should not leak memory during repeated errors", () => {
|
||||
@@ -346,11 +348,11 @@ Deno.test("Logger Additional Fallback Tests - Resource Cleanup - should not leak
|
||||
clearCapturedLogs();
|
||||
clearCapturedErrors();
|
||||
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const logger = new Logger({ format: "simple" });
|
||||
|
||||
// Break the formatter
|
||||
logger.formatters.simple = function () {
|
||||
throw new Error('Always fails');
|
||||
throw new Error("Always fails");
|
||||
};
|
||||
|
||||
// Log many times to check for memory leaks
|
||||
@@ -364,5 +366,4 @@ Deno.test("Logger Additional Fallback Tests - Resource Cleanup - should not leak
|
||||
// Check that we're not accumulating error state
|
||||
// (This is more of a smoke test - real memory leak detection would need different tools)
|
||||
assert(true); // If we get here without crashing, that's good
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { assertEquals, assert } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import { assert, assertEquals } from "@std/assert";
|
||||
import Logger from "../lib/logger.ts";
|
||||
import {
|
||||
setupMocks,
|
||||
getCapturedLogs,
|
||||
clearCapturedLogs,
|
||||
getCapturedLogs,
|
||||
getFirstLogAsJSON,
|
||||
} from './helpers/logger-test-helpers.js';
|
||||
setupMocks,
|
||||
} from "./helpers/logger-test-helpers.js";
|
||||
|
||||
// Setup and teardown for all tests
|
||||
setupMocks();
|
||||
|
||||
Deno.test("Logger JSON Formatter - Basic JSON Output - should produce valid JSON output", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("test message");
|
||||
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
@@ -24,36 +24,36 @@ Deno.test("Logger JSON Formatter - Basic JSON Output - should produce valid JSON
|
||||
|
||||
Deno.test("Logger JSON Formatter - Basic JSON Output - should include all required fields in JSON output", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json', callerLevel: 'info' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "json", callerLevel: "info" });
|
||||
logger.info("test message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
|
||||
assertEquals(parsed.level, 'info');
|
||||
assertEquals(parsed.level, "info");
|
||||
assertEquals(parsed.levelNumber, 2);
|
||||
assertEquals(parsed.msg, 'test message');
|
||||
assertEquals(typeof parsed.time, 'string');
|
||||
assertEquals(typeof parsed.pid, 'number');
|
||||
assertEquals(typeof parsed.hostname, 'string');
|
||||
assertEquals(parsed.msg, "test message");
|
||||
assertEquals(typeof parsed.time, "string");
|
||||
assertEquals(typeof parsed.pid, "number");
|
||||
assertEquals(typeof parsed.hostname, "string");
|
||||
assert(parsed.callerFile);
|
||||
assertEquals(typeof parsed.callerLine, 'number');
|
||||
assertEquals(typeof parsed.callerLine, "number");
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - Basic JSON Output - should format timestamp correctly based on time option", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json', time: 'short' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "json", time: "short" });
|
||||
logger.info("test message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
// Should be short format, not ISO
|
||||
assert(parsed.time.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/));
|
||||
assert(!parsed.time.includes('T'));
|
||||
assert(!parsed.time.includes('Z'));
|
||||
assert(!parsed.time.includes("T"));
|
||||
assert(!parsed.time.includes("Z"));
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - JSON Error Handling - should handle circular references in log entry", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Create a circular reference by modifying the logger's formatters
|
||||
const originalJsonFormatter = logger.formatters.json;
|
||||
@@ -67,33 +67,33 @@ Deno.test("Logger JSON Formatter - JSON Error Handling - should handle circular
|
||||
return originalJsonFormatter.call(this, logEntry);
|
||||
};
|
||||
|
||||
logger.info('test with circular reference');
|
||||
logger.info("test with circular reference");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
// Should be valid JSON despite circular reference
|
||||
const parsed = JSON.parse(logOutput);
|
||||
// Should contain error information
|
||||
assert(parsed.jsonError.includes('JSON stringify failed'));
|
||||
assertEquals(parsed.msg, 'test with circular reference');
|
||||
assert(parsed.jsonError.includes("JSON stringify failed"));
|
||||
assertEquals(parsed.msg, "test with circular reference");
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - JSON Error Handling - should handle JSON stringify errors with fallback", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Create a problematic object that will cause JSON.stringify to fail
|
||||
const problematic = {};
|
||||
Object.defineProperty(problematic, 'badProp', {
|
||||
Object.defineProperty(problematic, "badProp", {
|
||||
get() {
|
||||
throw new Error('Property access error');
|
||||
throw new Error("Property access error");
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
|
||||
// Test the formatter directly with a problematic object
|
||||
const problematicLogEntry = {
|
||||
level: 'info',
|
||||
msg: 'test message',
|
||||
level: "info",
|
||||
msg: "test message",
|
||||
problematic: problematic,
|
||||
};
|
||||
|
||||
@@ -101,12 +101,12 @@ Deno.test("Logger JSON Formatter - JSON Error Handling - should handle JSON stri
|
||||
|
||||
// Should produce valid JSON with error info
|
||||
const parsed = JSON.parse(result);
|
||||
assert(parsed.jsonError.includes('JSON stringify failed'));
|
||||
assert(parsed.jsonError.includes("JSON stringify failed"));
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - JSON Error Handling - should handle extreme JSON stringify failures", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// Create an object that will fail even the safe fallback
|
||||
// by mocking JSON.stringify to always throw
|
||||
@@ -116,22 +116,22 @@ Deno.test("Logger JSON Formatter - JSON Error Handling - should handle extreme J
|
||||
JSON.stringify = function (...args) {
|
||||
callCount++;
|
||||
if (callCount <= 2) {
|
||||
throw new Error('Mock JSON error');
|
||||
throw new Error("Mock JSON error");
|
||||
}
|
||||
return originalStringify.apply(this, args);
|
||||
};
|
||||
|
||||
try {
|
||||
const result = logger.formatters.json({
|
||||
level: 'error',
|
||||
msg: 'test message',
|
||||
level: "error",
|
||||
msg: "test message",
|
||||
});
|
||||
|
||||
// Should still produce valid JSON string even after multiple failures
|
||||
const parsed = JSON.parse(result);
|
||||
assertEquals(parsed.level, 'error');
|
||||
assertEquals(parsed.msg, 'test message');
|
||||
assert(parsed.jsonError.includes('Multiple JSON errors occurred'));
|
||||
assertEquals(parsed.level, "error");
|
||||
assertEquals(parsed.msg, "test message");
|
||||
assert(parsed.jsonError.includes("Multiple JSON errors occurred"));
|
||||
} finally {
|
||||
JSON.stringify = originalStringify;
|
||||
}
|
||||
@@ -139,7 +139,7 @@ Deno.test("Logger JSON Formatter - JSON Error Handling - should handle extreme J
|
||||
|
||||
Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should handle special characters", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info('Special chars: "quotes", \\backslash, \nnewline');
|
||||
|
||||
// Should produce valid JSON despite special characters
|
||||
@@ -148,26 +148,26 @@ Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should ha
|
||||
|
||||
Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should handle empty messages", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
assertEquals(parsed.msg, '');
|
||||
assertEquals(parsed.msg, "");
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should handle null and undefined arguments", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Value: %s', null);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Value: %s", null);
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
assertEquals(parsed.msg, 'Value: null');
|
||||
assertEquals(parsed.msg, "Value: null");
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should handle very long messages", () => {
|
||||
clearCapturedLogs();
|
||||
const longMessage = 'x'.repeat(10000);
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const longMessage = "x".repeat(10000);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info(longMessage);
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
@@ -176,9 +176,9 @@ Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should ha
|
||||
|
||||
Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should handle objects in messages", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const obj = { key: 'value', nested: { prop: 123 } };
|
||||
logger.info('Object: %j', obj);
|
||||
const logger = new Logger({ format: "json" });
|
||||
const obj = { key: "value", nested: { prop: 123 } };
|
||||
logger.info("Object: %j", obj);
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
assert(parsed.msg.includes('{"key":"value","nested":{"prop":123}}'));
|
||||
@@ -186,40 +186,40 @@ Deno.test("Logger JSON Formatter - Special Characters and Edge Cases - should ha
|
||||
|
||||
Deno.test("Logger JSON Formatter - All Log Levels in JSON - should log error messages with correct level", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.error('error message');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.error("error message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
assertEquals(parsed.level, 'error');
|
||||
assertEquals(parsed.level, "error");
|
||||
assertEquals(parsed.levelNumber, 0);
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - All Log Levels in JSON - should log warn messages with correct level", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.warn('warn message');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.warn("warn message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
assertEquals(parsed.level, 'warn');
|
||||
assertEquals(parsed.level, "warn");
|
||||
assertEquals(parsed.levelNumber, 1);
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - All Log Levels in JSON - should log info messages with correct level", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('info message');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("info message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
assertEquals(parsed.level, 'info');
|
||||
assertEquals(parsed.level, "info");
|
||||
assertEquals(parsed.levelNumber, 2);
|
||||
});
|
||||
|
||||
Deno.test("Logger JSON Formatter - All Log Levels in JSON - should log debug messages with correct level", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'debug', format: 'json' });
|
||||
logger.debug('debug message');
|
||||
const logger = new Logger({ level: "debug", format: "json" });
|
||||
logger.debug("debug message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
assertEquals(parsed.level, 'debug');
|
||||
assertEquals(parsed.level, "debug");
|
||||
assertEquals(parsed.levelNumber, 3);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,151 +1,159 @@
|
||||
import { assertEquals, assertThrows } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import Logger from "../lib/logger.ts";
|
||||
import {
|
||||
setupMocks,
|
||||
getCapturedLogs,
|
||||
clearCapturedLogs,
|
||||
} from './helpers/logger-test-helpers.js';
|
||||
getCapturedLogs,
|
||||
setupMocks,
|
||||
} from "./helpers/logger-test-helpers.js";
|
||||
|
||||
// Setup and teardown for all tests
|
||||
setupMocks();
|
||||
|
||||
Deno.test("Logger Level Management - Level Setting and Getting - should change log level with level() method", () => {
|
||||
const logger = new Logger();
|
||||
logger.level('debug');
|
||||
assertEquals(logger.options.level, 'debug');
|
||||
logger.level("debug");
|
||||
assertEquals(logger.options.level, "debug");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Level Setting and Getting - should return current level when called without arguments", () => {
|
||||
const logger = new Logger({ level: 'debug' });
|
||||
assertEquals(logger.level(), 'debug');
|
||||
const logger = new Logger({ level: "debug" });
|
||||
assertEquals(logger.level(), "debug");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Level Setting and Getting - should return new level when setting level", () => {
|
||||
const logger = new Logger();
|
||||
const result = logger.level('error');
|
||||
assertEquals(result, 'error');
|
||||
assertEquals(logger.options.level, 'error');
|
||||
const result = logger.level("error");
|
||||
assertEquals(result, "error");
|
||||
assertEquals(logger.options.level, "error");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Level Setting and Getting - should throw error for invalid log level", () => {
|
||||
const logger = new Logger();
|
||||
assertThrows(() => {
|
||||
logger.level('invalid');
|
||||
}, Error, "Invalid log level: invalid");
|
||||
assertThrows(
|
||||
() => {
|
||||
logger.level("invalid");
|
||||
},
|
||||
Error,
|
||||
"Invalid log level: invalid",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Level Setting and Getting - should allow method chaining after setting level", () => {
|
||||
const logger = new Logger();
|
||||
// This should not throw and should return a level
|
||||
const result = logger.level('warn');
|
||||
assertEquals(result, 'warn');
|
||||
assertEquals(typeof result, 'string');
|
||||
const result = logger.level("warn");
|
||||
assertEquals(result, "warn");
|
||||
assertEquals(typeof result, "string");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - setLevel Method - should have setLevel method as alias", () => {
|
||||
const logger = new Logger();
|
||||
assertEquals(typeof logger.setLevel, 'function');
|
||||
assertEquals(typeof logger.setLevel, "function");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - setLevel Method - should set level correctly with setLevel method", () => {
|
||||
const logger = new Logger();
|
||||
const result = logger.setLevel('debug');
|
||||
assertEquals(result, 'debug');
|
||||
assertEquals(logger.options.level, 'debug');
|
||||
const result = logger.setLevel("debug");
|
||||
assertEquals(result, "debug");
|
||||
assertEquals(logger.options.level, "debug");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - setLevel Method - should return current level with setLevel when no args", () => {
|
||||
const logger = new Logger({ level: 'warn' });
|
||||
const logger = new Logger({ level: "warn" });
|
||||
const result = logger.setLevel();
|
||||
assertEquals(result, 'warn');
|
||||
assertEquals(result, "warn");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - setLevel Method - should throw error for invalid level in setLevel", () => {
|
||||
const logger = new Logger();
|
||||
assertThrows(() => {
|
||||
logger.setLevel('invalid');
|
||||
}, Error, "Invalid log level: invalid");
|
||||
assertThrows(
|
||||
() => {
|
||||
logger.setLevel("invalid");
|
||||
},
|
||||
Error,
|
||||
"Invalid log level: invalid",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - setLevel Method - should maintain consistency between level() and setLevel()", () => {
|
||||
const logger = new Logger();
|
||||
|
||||
logger.level('error');
|
||||
assertEquals(logger.setLevel(), 'error');
|
||||
logger.level("error");
|
||||
assertEquals(logger.setLevel(), "error");
|
||||
|
||||
logger.setLevel('debug');
|
||||
assertEquals(logger.level(), 'debug');
|
||||
logger.setLevel("debug");
|
||||
assertEquals(logger.level(), "debug");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - setLevel Method - should support fluent interface pattern", () => {
|
||||
const logger = new Logger();
|
||||
|
||||
// This demonstrates the fluent interface working
|
||||
const currentLevel = logger.level('warn');
|
||||
assertEquals(currentLevel, 'warn');
|
||||
const currentLevel = logger.level("warn");
|
||||
assertEquals(currentLevel, "warn");
|
||||
|
||||
// Both methods should return the current level for chaining
|
||||
assertEquals(logger.level('info'), 'info');
|
||||
assertEquals(logger.setLevel('debug'), 'debug');
|
||||
assertEquals(logger.level("info"), "info");
|
||||
assertEquals(logger.setLevel("debug"), "debug");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Log Level Filtering - should filter debug messages when level is info", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'info' });
|
||||
logger.debug('debug message');
|
||||
const logger = new Logger({ level: "info" });
|
||||
logger.debug("debug message");
|
||||
assertEquals(getCapturedLogs().length, 0);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Log Level Filtering - should show info messages when level is info", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'info' });
|
||||
logger.info('info message');
|
||||
const logger = new Logger({ level: "info" });
|
||||
logger.info("info message");
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Log Level Filtering - should show error messages at any level", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'error' });
|
||||
logger.error('error message');
|
||||
const logger = new Logger({ level: "error" });
|
||||
logger.error("error message");
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Log Level Filtering - should filter warn and info when level is error", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'error' });
|
||||
logger.warn('warn message');
|
||||
logger.info('info message');
|
||||
const logger = new Logger({ level: "error" });
|
||||
logger.warn("warn message");
|
||||
logger.info("info message");
|
||||
assertEquals(getCapturedLogs().length, 0);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Log Level Filtering - should show all messages when level is debug", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'debug' });
|
||||
logger.error('error message');
|
||||
logger.warn('warn message');
|
||||
logger.info('info message');
|
||||
logger.debug('debug message');
|
||||
const logger = new Logger({ level: "debug" });
|
||||
logger.error("error message");
|
||||
logger.warn("warn message");
|
||||
logger.info("info message");
|
||||
logger.debug("debug message");
|
||||
assertEquals(getCapturedLogs().length, 4);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Log Level Filtering - should show warn and above when level is warn", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'warn' });
|
||||
logger.error('error message');
|
||||
logger.warn('warn message');
|
||||
logger.info('info message');
|
||||
logger.debug('debug message');
|
||||
const logger = new Logger({ level: "warn" });
|
||||
logger.error("error message");
|
||||
logger.warn("warn message");
|
||||
logger.info("info message");
|
||||
logger.debug("debug message");
|
||||
assertEquals(getCapturedLogs().length, 2);
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Silent Level - should suppress all output when level is silent", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'silent' });
|
||||
const logger = new Logger({ level: "silent" });
|
||||
|
||||
logger.error('error message');
|
||||
logger.warn('warn message');
|
||||
logger.info('info message');
|
||||
logger.debug('debug message');
|
||||
logger.error("error message");
|
||||
logger.warn("warn message");
|
||||
logger.info("info message");
|
||||
logger.debug("debug message");
|
||||
|
||||
// No messages should be logged
|
||||
assertEquals(getCapturedLogs().length, 0);
|
||||
@@ -153,21 +161,21 @@ Deno.test("Logger Level Management - Silent Level - should suppress all output w
|
||||
|
||||
Deno.test("Logger Level Management - Silent Level - should allow setting level to silent", () => {
|
||||
const logger = new Logger();
|
||||
const result = logger.level('silent');
|
||||
assertEquals(result, 'silent');
|
||||
assertEquals(logger.options.level, 'silent');
|
||||
const result = logger.level("silent");
|
||||
assertEquals(result, "silent");
|
||||
assertEquals(logger.options.level, "silent");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Silent Level - should work with setLevel for silent level", () => {
|
||||
const logger = new Logger();
|
||||
const result = logger.setLevel('silent');
|
||||
assertEquals(result, 'silent');
|
||||
assertEquals(logger.options.level, 'silent');
|
||||
const result = logger.setLevel("silent");
|
||||
assertEquals(result, "silent");
|
||||
assertEquals(logger.options.level, "silent");
|
||||
});
|
||||
|
||||
Deno.test("Logger Level Management - Silent Level - should remain silent after multiple log attempts", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'silent' });
|
||||
const logger = new Logger({ level: "silent" });
|
||||
|
||||
// Try logging multiple times
|
||||
for (let i = 0; i < 5; i++) {
|
||||
@@ -183,23 +191,23 @@ Deno.test("Logger Level Management - Silent Level - should remain silent after m
|
||||
|
||||
Deno.test("Logger Level Management - Dynamic Level Changes - should respect level changes during runtime", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ level: 'error' });
|
||||
const logger = new Logger({ level: "error" });
|
||||
|
||||
// Should not log at info level
|
||||
logger.info('info message 1');
|
||||
logger.info("info message 1");
|
||||
assertEquals(getCapturedLogs().length, 0);
|
||||
|
||||
// Change to info level
|
||||
logger.level('info');
|
||||
logger.level("info");
|
||||
|
||||
// Should now log info messages
|
||||
logger.info('info message 2');
|
||||
logger.info("info message 2");
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
|
||||
// Change to silent
|
||||
logger.level('silent');
|
||||
logger.level("silent");
|
||||
|
||||
// Should not log anything
|
||||
logger.error('error message');
|
||||
logger.error("error message");
|
||||
assertEquals(getCapturedLogs().length, 1); // Still just the previous info message
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { assertEquals, assert } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import { assert, assertEquals } from "@std/assert";
|
||||
import Logger from "../lib/logger.ts";
|
||||
import {
|
||||
setupMocks,
|
||||
getCapturedLogs,
|
||||
clearCapturedLogs,
|
||||
} from './helpers/logger-test-helpers.js';
|
||||
getCapturedLogs,
|
||||
setupMocks,
|
||||
} from "./helpers/logger-test-helpers.js";
|
||||
|
||||
// Setup and teardown for all tests
|
||||
setupMocks();
|
||||
@@ -14,12 +14,12 @@ Deno.test("Logger Robustness - Edge Cases and Data Handling - should not crash o
|
||||
const logger = new Logger();
|
||||
|
||||
// This should not throw
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
});
|
||||
|
||||
Deno.test("Logger Robustness - Edge Cases and Data Handling - should handle undefined and null messages gracefully", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
// These should not crash
|
||||
logger.info(undefined);
|
||||
@@ -31,14 +31,14 @@ Deno.test("Logger Robustness - Edge Cases and Data Handling - should handle unde
|
||||
const parsed1 = JSON.parse(logs[0]);
|
||||
const parsed2 = JSON.parse(logs[1]);
|
||||
|
||||
assertEquals(parsed1.msg, 'undefined');
|
||||
assertEquals(parsed2.msg, 'null');
|
||||
assertEquals(parsed1.msg, "undefined");
|
||||
assertEquals(parsed2.msg, "null");
|
||||
});
|
||||
|
||||
Deno.test("Logger Robustness - Edge Cases and Data Handling - should handle extremely large messages", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const hugeMessage = 'x'.repeat(100000);
|
||||
const logger = new Logger({ format: "json" });
|
||||
const hugeMessage = "x".repeat(100000);
|
||||
|
||||
logger.info(hugeMessage);
|
||||
|
||||
@@ -48,12 +48,12 @@ Deno.test("Logger Robustness - Edge Cases and Data Handling - should handle extr
|
||||
|
||||
Deno.test("Logger Robustness - Edge Cases and Data Handling - should handle circular objects in message formatting", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
const circular = { name: 'test' };
|
||||
const circular = { name: "test" };
|
||||
circular.self = circular;
|
||||
|
||||
logger.info('Circular: %j', circular);
|
||||
logger.info("Circular: %j", circular);
|
||||
|
||||
// Should still log something
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
@@ -61,7 +61,7 @@ Deno.test("Logger Robustness - Edge Cases and Data Handling - should handle circ
|
||||
|
||||
Deno.test("Logger Robustness - Performance and Memory - should handle rapid consecutive logging without issues", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
logger.info(`rapid message ${i}`);
|
||||
@@ -72,7 +72,7 @@ Deno.test("Logger Robustness - Performance and Memory - should handle rapid cons
|
||||
|
||||
Deno.test("Logger Robustness - Performance and Memory - should handle repeated logging operations efficiently", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const logger = new Logger({ format: "simple" });
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
@@ -91,8 +91,8 @@ Deno.test("Logger Robustness - Performance and Memory - should handle repeated l
|
||||
|
||||
Deno.test("Logger Robustness - Performance and Memory - should handle mixed format types in rapid succession", () => {
|
||||
clearCapturedLogs();
|
||||
const jsonLogger = new Logger({ format: 'json' });
|
||||
const simpleLogger = new Logger({ format: 'simple' });
|
||||
const jsonLogger = new Logger({ format: "json" });
|
||||
const simpleLogger = new Logger({ format: "simple" });
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
jsonLogger.info(`json message ${i}`);
|
||||
@@ -104,40 +104,40 @@ Deno.test("Logger Robustness - Performance and Memory - should handle mixed form
|
||||
|
||||
Deno.test("Logger Robustness - Complex Data Structures - should handle deeply nested objects", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
const deepObject = {
|
||||
level1: { level2: { level3: { level4: { value: 'deep' } } } },
|
||||
level1: { level2: { level3: { level4: { value: "deep" } } } },
|
||||
};
|
||||
|
||||
logger.info('Deep object: %j', deepObject);
|
||||
logger.info("Deep object: %j", deepObject);
|
||||
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
});
|
||||
|
||||
Deno.test("Logger Robustness - Complex Data Structures - should handle arrays with mixed data types", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
const mixedArray = [
|
||||
1,
|
||||
'string',
|
||||
"string",
|
||||
{ obj: true },
|
||||
[1, 2, 3],
|
||||
null,
|
||||
undefined,
|
||||
];
|
||||
|
||||
logger.info('Mixed array: %j', mixedArray);
|
||||
logger.info("Mixed array: %j", mixedArray);
|
||||
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
});
|
||||
|
||||
Deno.test("Logger Robustness - Complex Data Structures - should handle special characters and unicode", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
|
||||
const specialMessage = 'Special chars: \n\t\r\\"\'🚀 Unicode: こんにちは';
|
||||
const specialMessage = "Special chars: \n\t\r\\\"'🚀 Unicode: こんにちは";
|
||||
|
||||
logger.info(specialMessage);
|
||||
|
||||
|
||||
@@ -1,182 +1,182 @@
|
||||
import { assertEquals, assert } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import { assert, assertEquals } from "@std/assert";
|
||||
import Logger from "../lib/logger.ts";
|
||||
import {
|
||||
setupMocks,
|
||||
getCapturedLogs,
|
||||
clearCapturedLogs,
|
||||
setTTYMode,
|
||||
getCapturedLogs,
|
||||
restoreTTY,
|
||||
} from './helpers/logger-test-helpers.js';
|
||||
setTTYMode,
|
||||
setupMocks,
|
||||
} from "./helpers/logger-test-helpers.js";
|
||||
|
||||
// Setup and teardown for all tests
|
||||
setupMocks();
|
||||
|
||||
Deno.test("Logger Simple Formatter - Basic Simple Format - should produce simple text format", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.info("test message");
|
||||
|
||||
assertEquals(getCapturedLogs().length, 1);
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should contain timestamp, level, caller, and message
|
||||
assert(logOutput.includes('[INFO ]'));
|
||||
assert(logOutput.includes('test message'));
|
||||
assert(logOutput.includes("[INFO ]"));
|
||||
assert(logOutput.includes("test message"));
|
||||
// Should contain short timestamp by default
|
||||
assert(logOutput.match(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}\]/));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Basic Simple Format - should pad log levels correctly", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple', level: 'debug' });
|
||||
logger.error('error msg');
|
||||
logger.debug('debug msg');
|
||||
const logger = new Logger({ format: "simple", level: "debug" });
|
||||
logger.error("error msg");
|
||||
logger.debug("debug msg");
|
||||
|
||||
const logs = getCapturedLogs();
|
||||
assert(logs[0].includes('[ERROR]'));
|
||||
assert(logs[1].includes('[DEBUG]'));
|
||||
assert(logs[0].includes("[ERROR]"));
|
||||
assert(logs[1].includes("[DEBUG]"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Basic Simple Format - should include caller information", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple', callerLevel: 'info' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "simple", callerLevel: "info" });
|
||||
logger.info("test message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
// Should contain filename and line number
|
||||
assert(logOutput.includes('.js:'));
|
||||
assert(logOutput.includes(".js:"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Basic Simple Format - should format with long timestamp when specified", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple', time: 'long' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "simple", time: "long" });
|
||||
logger.info("test message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should contain long time format in brackets
|
||||
assert(
|
||||
logOutput.match(/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\]/)
|
||||
logOutput.match(/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\]/),
|
||||
);
|
||||
assert(logOutput.includes('T'));
|
||||
assert(logOutput.includes('Z'));
|
||||
assert(logOutput.includes("T"));
|
||||
assert(logOutput.includes("Z"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - All Log Levels in Simple Format - should format error level correctly", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.error('error message');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.error("error message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
assert(logOutput.includes('[ERROR]'));
|
||||
assert(logOutput.includes('error message'));
|
||||
assert(logOutput.includes("[ERROR]"));
|
||||
assert(logOutput.includes("error message"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - All Log Levels in Simple Format - should format warn level correctly", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.warn('warn message');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.warn("warn message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
assert(logOutput.includes('[WARN ]'));
|
||||
assert(logOutput.includes('warn message'));
|
||||
assert(logOutput.includes("[WARN ]"));
|
||||
assert(logOutput.includes("warn message"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - All Log Levels in Simple Format - should format info level correctly", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.info('info message');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.info("info message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
assert(logOutput.includes('[INFO ]'));
|
||||
assert(logOutput.includes('info message'));
|
||||
assert(logOutput.includes("[INFO ]"));
|
||||
assert(logOutput.includes("info message"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - All Log Levels in Simple Format - should format debug level correctly", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple', level: 'debug' });
|
||||
logger.debug('debug message');
|
||||
const logger = new Logger({ format: "simple", level: "debug" });
|
||||
logger.debug("debug message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
assert(logOutput.includes('[DEBUG]'));
|
||||
assert(logOutput.includes('debug message'));
|
||||
assert(logOutput.includes("[DEBUG]"));
|
||||
assert(logOutput.includes("debug message"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Color Handling - should include color codes when output is TTY", () => {
|
||||
clearCapturedLogs();
|
||||
setTTYMode(true);
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.error('error message');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.error("error message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
// Should contain ANSI color codes
|
||||
assert(logOutput.includes('\x1b[91m')); // red for error
|
||||
assert(logOutput.includes('\x1b[0m')); // reset
|
||||
assert(logOutput.includes("\x1b[91m")); // red for error
|
||||
assert(logOutput.includes("\x1b[0m")); // reset
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Color Handling - should not include color codes when output is redirected", () => {
|
||||
clearCapturedLogs();
|
||||
setTTYMode(false);
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.error('error message');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.error("error message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
// Should not contain ANSI color codes
|
||||
assert(!logOutput.includes('\x1b['));
|
||||
assert(!logOutput.includes("\x1b["));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Color Handling - should use appropriate colors for different levels", () => {
|
||||
clearCapturedLogs();
|
||||
setTTYMode(true);
|
||||
const logger = new Logger({ format: 'simple', level: 'debug' });
|
||||
const logger = new Logger({ format: "simple", level: "debug" });
|
||||
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.info('info');
|
||||
logger.debug('debug');
|
||||
logger.error("error");
|
||||
logger.warn("warn");
|
||||
logger.info("info");
|
||||
logger.debug("debug");
|
||||
|
||||
const logs = getCapturedLogs();
|
||||
|
||||
// Error should be red
|
||||
assert(logs[0].includes('\x1b[91m'));
|
||||
assert(logs[0].includes("\x1b[91m"));
|
||||
// Warn should be yellow
|
||||
assert(logs[1].includes('\x1b[33m'));
|
||||
assert(logs[1].includes("\x1b[33m"));
|
||||
// Info and debug might have different or no colors, but should have reset codes
|
||||
assert(logs[2].includes('\x1b[0m'));
|
||||
assert(logs[3].includes('\x1b[0m'));
|
||||
assert(logs[2].includes("\x1b[0m"));
|
||||
assert(logs[3].includes("\x1b[0m"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Color Handling - should respect custom color configuration", () => {
|
||||
clearCapturedLogs();
|
||||
setTTYMode(true);
|
||||
const logger = new Logger({
|
||||
format: 'simple',
|
||||
format: "simple",
|
||||
colours: {
|
||||
error: '\x1b[31m', // different red
|
||||
warn: '\x1b[35m', // magenta instead of yellow
|
||||
error: "\x1b[31m", // different red
|
||||
warn: "\x1b[35m", // magenta instead of yellow
|
||||
},
|
||||
});
|
||||
|
||||
logger.error('error message');
|
||||
logger.warn('warn message');
|
||||
logger.error("error message");
|
||||
logger.warn("warn message");
|
||||
|
||||
const logs = getCapturedLogs();
|
||||
assert(logs[0].includes('\x1b[31m'));
|
||||
assert(logs[1].includes('\x1b[35m'));
|
||||
assert(logs[0].includes("\x1b[31m"));
|
||||
assert(logs[1].includes("\x1b[35m"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Message Formatting in Simple Mode - should handle multiple arguments", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.info('Hello %s, you are %d years old', 'John', 25);
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.info("Hello %s, you are %d years old", "John", 25);
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
assert(logOutput.includes('Hello John, you are 25 years old'));
|
||||
assert(logOutput.includes("Hello John, you are 25 years old"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - Message Formatting in Simple Mode - should handle special characters", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.info('Special chars: "quotes", \\backslash, \nnewline');
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
@@ -185,12 +185,12 @@ Deno.test("Logger Simple Formatter - Message Formatting in Simple Mode - should
|
||||
|
||||
Deno.test("Logger Simple Formatter - Message Formatting in Simple Mode - should handle empty messages", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.info('');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.info("");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
// Should still have the level and timestamp parts
|
||||
assert(logOutput.includes('[INFO ]'));
|
||||
assert(logOutput.includes("[INFO ]"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Simple Formatter - TTY Detection Integration - should detect TTY mode changes correctly", () => {
|
||||
@@ -198,20 +198,20 @@ Deno.test("Logger Simple Formatter - TTY Detection Integration - should detect T
|
||||
|
||||
// Test with TTY
|
||||
setTTYMode(true);
|
||||
const ttyLogger = new Logger({ format: 'simple' });
|
||||
ttyLogger.error('tty error');
|
||||
const ttyLogger = new Logger({ format: "simple" });
|
||||
ttyLogger.error("tty error");
|
||||
|
||||
// Test without TTY
|
||||
setTTYMode(false);
|
||||
const noTtyLogger = new Logger({ format: 'simple' });
|
||||
noTtyLogger.error('no tty error');
|
||||
const noTtyLogger = new Logger({ format: "simple" });
|
||||
noTtyLogger.error("no tty error");
|
||||
|
||||
const logs = getCapturedLogs();
|
||||
|
||||
// First should have colors, second should not
|
||||
assert(logs[0].includes('\x1b['));
|
||||
assert(!logs[1].includes('\x1b['));
|
||||
assert(logs[0].includes("\x1b["));
|
||||
assert(!logs[1].includes("\x1b["));
|
||||
});
|
||||
|
||||
// Cleanup
|
||||
restoreTTY();
|
||||
restoreTTY();
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import { assertEquals, assertThrows, assert } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import { assert, assertEquals, assertThrows } from "@std/assert";
|
||||
import Logger from "../lib/logger.ts";
|
||||
import {
|
||||
setupMocks,
|
||||
getCapturedLogs,
|
||||
clearCapturedLogs,
|
||||
getCapturedLogs,
|
||||
getFirstLogAsJSON,
|
||||
} from './helpers/logger-test-helpers.js';
|
||||
setupMocks,
|
||||
} from "./helpers/logger-test-helpers.js";
|
||||
|
||||
// Setup and teardown for all tests
|
||||
setupMocks();
|
||||
|
||||
Deno.test("Logger Time Formatting - Default Time Format - should default to short time format", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("test message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
|
||||
// Short format should be YYYY-MM-DD HH:MM (without seconds)
|
||||
assert(parsed.time.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/));
|
||||
assert(!parsed.time.includes('T'));
|
||||
assert(!parsed.time.includes('Z'));
|
||||
assert(!parsed.time.includes('.'));
|
||||
assert(!parsed.time.includes("T"));
|
||||
assert(!parsed.time.includes("Z"));
|
||||
assert(!parsed.time.includes("."));
|
||||
});
|
||||
|
||||
Deno.test("Logger Time Formatting - Default Time Format - should include time option in logger options", () => {
|
||||
const shortLogger = new Logger({ time: 'short' });
|
||||
const longLogger = new Logger({ time: 'long' });
|
||||
const shortLogger = new Logger({ time: "short" });
|
||||
const longLogger = new Logger({ time: "long" });
|
||||
const defaultLogger = new Logger();
|
||||
|
||||
assertEquals(shortLogger.options.time, 'short');
|
||||
assertEquals(longLogger.options.time, 'long');
|
||||
assertEquals(defaultLogger.options.time, 'short'); // default
|
||||
assertEquals(shortLogger.options.time, "short");
|
||||
assertEquals(longLogger.options.time, "long");
|
||||
assertEquals(defaultLogger.options.time, "short"); // default
|
||||
});
|
||||
|
||||
Deno.test("Logger Time Formatting - Short Time Format - should format time as short when time option is 'short'", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ time: 'short', format: 'json' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ time: "short", format: "json" });
|
||||
logger.info("test message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
|
||||
@@ -48,30 +48,30 @@ Deno.test("Logger Time Formatting - Short Time Format - should format time as sh
|
||||
|
||||
Deno.test("Logger Time Formatting - Short Time Format - should work with simple formatter and short time", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ time: 'short', format: 'simple' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ time: "short", format: "simple" });
|
||||
logger.info("test message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should contain short time format in brackets
|
||||
assert(logOutput.match(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}\]/));
|
||||
assert(!logOutput.includes('T'));
|
||||
assert(!logOutput.includes('Z'));
|
||||
assert(!logOutput.includes("T"));
|
||||
assert(!logOutput.includes("Z"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Time Formatting - Short Time Format - should truncate time correctly in short format", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ time: 'short', format: 'json' });
|
||||
const logger = new Logger({ time: "short", format: "json" });
|
||||
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
|
||||
// Short format should not have seconds or milliseconds
|
||||
assert(
|
||||
!parsed.time.includes(':') || parsed.time.split(':').length === 2
|
||||
!parsed.time.includes(":") || parsed.time.split(":").length === 2,
|
||||
);
|
||||
assert(!parsed.time.includes('.'));
|
||||
assert(!parsed.time.includes("."));
|
||||
|
||||
// Should be exactly 16 characters: YYYY-MM-DD HH:MM
|
||||
assertEquals(parsed.time.length, 16);
|
||||
@@ -79,46 +79,46 @@ Deno.test("Logger Time Formatting - Short Time Format - should truncate time cor
|
||||
|
||||
Deno.test("Logger Time Formatting - Long Time Format - should format time as long ISO string when time is 'long'", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ time: 'long', format: 'json' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ time: "long", format: "json" });
|
||||
logger.info("test message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
|
||||
// Long format should be full ISO string
|
||||
assert(parsed.time.includes('T'));
|
||||
assert(parsed.time.includes('Z'));
|
||||
assert(parsed.time.includes('.'));
|
||||
assert(parsed.time.includes("T"));
|
||||
assert(parsed.time.includes("Z"));
|
||||
assert(parsed.time.includes("."));
|
||||
|
||||
// Should be valid ISO string
|
||||
new Date(parsed.time); // This should not throw
|
||||
|
||||
// Should match ISO format pattern
|
||||
assert(
|
||||
parsed.time.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/)
|
||||
parsed.time.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Time Formatting - Long Time Format - should work with simple formatter and long time", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ time: 'long', format: 'simple' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ time: "long", format: "simple" });
|
||||
logger.info("test message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should contain long time format in brackets
|
||||
assert(
|
||||
logOutput.match(/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\]/)
|
||||
logOutput.match(/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\]/),
|
||||
);
|
||||
assert(logOutput.includes('T'));
|
||||
assert(logOutput.includes('Z'));
|
||||
assert(logOutput.includes("T"));
|
||||
assert(logOutput.includes("Z"));
|
||||
});
|
||||
|
||||
Deno.test("Logger Time Formatting - Long Time Format - should preserve time precision in long format", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ time: 'long', format: 'json' });
|
||||
const logger = new Logger({ time: "long", format: "json" });
|
||||
|
||||
const startTime = Date.now();
|
||||
logger.info('test message');
|
||||
logger.info("test message");
|
||||
const endTime = Date.now();
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
@@ -129,15 +129,15 @@ Deno.test("Logger Time Formatting - Long Time Format - should preserve time prec
|
||||
assert(logTime <= endTime);
|
||||
|
||||
// Should have millisecond precision
|
||||
assert(parsed.time.includes('.'));
|
||||
assert(parsed.time.includes("."));
|
||||
});
|
||||
|
||||
Deno.test("Logger Time Formatting - Time Format Consistency - should use consistent time format across multiple log calls", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ time: 'short', format: 'json' });
|
||||
const logger = new Logger({ time: "short", format: "json" });
|
||||
|
||||
logger.info('first message');
|
||||
logger.warn('second message');
|
||||
logger.info("first message");
|
||||
logger.warn("second message");
|
||||
|
||||
const logs = getCapturedLogs();
|
||||
const parsed1 = JSON.parse(logs[0]);
|
||||
@@ -150,34 +150,42 @@ Deno.test("Logger Time Formatting - Time Format Consistency - should use consist
|
||||
|
||||
Deno.test("Logger Time Formatting - Time Option Validation - should validate time option in constructor", () => {
|
||||
// Valid options should not throw
|
||||
new Logger({ time: 'long' });
|
||||
new Logger({ time: 'short' });
|
||||
new Logger({ time: "long" });
|
||||
new Logger({ time: "short" });
|
||||
|
||||
// Invalid option should throw
|
||||
assertThrows(() => {
|
||||
new Logger({ time: 'medium' });
|
||||
}, Error, "Invalid time: medium. Valid times are: long, short");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ time: "medium" });
|
||||
},
|
||||
Error,
|
||||
"Invalid time: medium. Valid times are: long, short",
|
||||
);
|
||||
|
||||
assertThrows(() => {
|
||||
new Logger({ time: 'invalid' });
|
||||
}, Error, "Invalid time: invalid. Valid times are: long, short");
|
||||
assertThrows(
|
||||
() => {
|
||||
new Logger({ time: "invalid" });
|
||||
},
|
||||
Error,
|
||||
"Invalid time: invalid. Valid times are: long, short",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Logger Time Formatting - Backward Compatibility - should maintain existing behavior for existing code", () => {
|
||||
clearCapturedLogs();
|
||||
|
||||
// Code that doesn't specify time option should work as before
|
||||
const logger = new Logger({ format: 'json', level: 'info' });
|
||||
logger.info('test message');
|
||||
const logger = new Logger({ format: "json", level: "info" });
|
||||
logger.info("test message");
|
||||
|
||||
const parsed = getFirstLogAsJSON();
|
||||
|
||||
// Should still have all expected fields
|
||||
assertEquals(parsed.level, 'info');
|
||||
assertEquals(parsed.msg, 'test message');
|
||||
assertEquals(typeof parsed.time, 'string');
|
||||
assertEquals(typeof parsed.pid, 'number');
|
||||
assertEquals(typeof parsed.hostname, 'string');
|
||||
assertEquals(parsed.level, "info");
|
||||
assertEquals(parsed.msg, "test message");
|
||||
assertEquals(typeof parsed.time, "string");
|
||||
assertEquals(typeof parsed.pid, "number");
|
||||
assertEquals(typeof parsed.hostname, "string");
|
||||
|
||||
// Time should be in short format (new default)
|
||||
assert(parsed.time.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/));
|
||||
@@ -185,16 +193,16 @@ Deno.test("Logger Time Formatting - Backward Compatibility - should maintain exi
|
||||
|
||||
Deno.test("Logger Time Formatting - Backward Compatibility - should not break existing simple formatter tests", () => {
|
||||
clearCapturedLogs();
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.warn('warning message');
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.warn("warning message");
|
||||
|
||||
const logOutput = getCapturedLogs()[0];
|
||||
|
||||
// Should still contain expected elements
|
||||
assert(logOutput.includes('[WARN ]'));
|
||||
assert(logOutput.includes('warning message'));
|
||||
assert(logOutput.includes('.js:'));
|
||||
assert(logOutput.includes("[WARN ]"));
|
||||
assert(logOutput.includes("warning message"));
|
||||
assert(logOutput.includes(".js:"));
|
||||
|
||||
// Should use short time format (new default)
|
||||
assert(logOutput.match(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}\]/));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,89 +1,89 @@
|
||||
import { assertEquals, assertMatch } from "@std/assert";
|
||||
import Logger from '../lib/logger.ts';
|
||||
import Logger from "../lib/logger.ts";
|
||||
|
||||
Deno.test("Logger util.format functionality - Format specifiers - should handle %s string formatting", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('User %s logged in', 'john');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("User %s logged in", "john");
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'User john logged in');
|
||||
assertEquals(output.msg, "User john logged in");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Format specifiers - should handle %d number formatting", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('User has %d points', 100);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("User has %d points", 100);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'User has 100 points');
|
||||
assertEquals(output.msg, "User has 100 points");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Format specifiers - should handle %i integer formatting", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Value: %i', 42.7);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Value: %i", 42.7);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Value: 42');
|
||||
assertEquals(output.msg, "Value: 42");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Format specifiers - should handle %f float formatting", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Price: %f', 19.99);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Price: %f", 19.99);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Price: 19.99');
|
||||
assertEquals(output.msg, "Price: 19.99");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Format specifiers - should handle %j JSON formatting", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const obj = { name: 'test', value: 42 };
|
||||
logger.info('Config: %j', obj);
|
||||
const logger = new Logger({ format: "json" });
|
||||
const obj = { name: "test", value: 42 };
|
||||
logger.info("Config: %j", obj);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Config: {"name":"test","value":42}');
|
||||
@@ -93,43 +93,43 @@ Deno.test("Logger util.format functionality - Format specifiers - should handle
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Format specifiers - should handle %% literal percentage", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Progress: 50%% complete');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Progress: 50%% complete");
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Progress: 50%% complete');
|
||||
assertEquals(output.msg, "Progress: 50%% complete");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Multiple format specifiers - should handle multiple format specifiers", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info(
|
||||
'User %s has %d points and %f%% completion',
|
||||
'alice',
|
||||
"User %s has %d points and %f%% completion",
|
||||
"alice",
|
||||
150,
|
||||
75.5
|
||||
75.5,
|
||||
);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(
|
||||
output.msg,
|
||||
'User alice has 150 points and 75.5% completion'
|
||||
"User alice has 150 points and 75.5% completion",
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -137,26 +137,26 @@ Deno.test("Logger util.format functionality - Multiple format specifiers - shoul
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Multiple format specifiers - should handle mixed format specifiers with JSON", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
const config = { debug: true, port: 3000 };
|
||||
logger.info(
|
||||
'Server %s running on port %d with config %j',
|
||||
'api',
|
||||
"Server %s running on port %d with config %j",
|
||||
"api",
|
||||
8080,
|
||||
config
|
||||
config,
|
||||
);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(
|
||||
output.msg,
|
||||
'Server api running on port 8080 with config {"debug":true,"port":3000}'
|
||||
'Server api running on port 8080 with config {"debug":true,"port":3000}',
|
||||
);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
@@ -164,34 +164,34 @@ Deno.test("Logger util.format functionality - Multiple format specifiers - shoul
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Multiple arguments without format specifiers - should handle multiple arguments without format specifiers", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Message', 'arg1', 'arg2', 123);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Message", "arg1", "arg2", 123);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Message arg1 arg2 123');
|
||||
assertEquals(output.msg, "Message arg1 arg2 123");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Multiple arguments without format specifiers - should handle mixed objects and primitives", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const obj = { key: 'value' };
|
||||
logger.info('Data:', obj, 42, true);
|
||||
const logger = new Logger({ format: "json" });
|
||||
const obj = { key: "value" };
|
||||
logger.info("Data:", obj, 42, true);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, "Data: { key: 'value' } 42 true");
|
||||
@@ -201,89 +201,89 @@ Deno.test("Logger util.format functionality - Multiple arguments without format
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Edge cases - should handle more format specifiers than arguments", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Hello %s, you are %d years old', 'John');
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Hello %s, you are %d years old", "John");
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Hello John, you are %d years old');
|
||||
assertEquals(output.msg, "Hello John, you are %d years old");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Edge cases - should handle more arguments than format specifiers", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Hello %s', 'John', 'extra', 'args', 123);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Hello %s", "John", "extra", "args", 123);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Hello John extra args 123');
|
||||
assertEquals(output.msg, "Hello John extra args 123");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Edge cases - should handle null and undefined values", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
logger.info('Values: %s %s %d', null, undefined, null);
|
||||
const logger = new Logger({ format: "json" });
|
||||
logger.info("Values: %s %s %d", null, undefined, null);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Values: null undefined 0');
|
||||
assertEquals(output.msg, "Values: null undefined 0");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Edge cases - should handle arrays and objects without %j", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
const arr = [1, 2, 3];
|
||||
const obj = { a: 1 };
|
||||
logger.info('Data %s and %s', arr, obj);
|
||||
logger.info("Data %s and %s", arr, obj);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(output.msg, 'Data [ 1, 2, 3 ] and { a: 1 }');
|
||||
assertEquals(output.msg, "Data [ 1, 2, 3 ] and { a: 1 }");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Simple format output - should format messages correctly in simple format", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
logger.info('User %s has %d points', 'bob', 200);
|
||||
const logger = new Logger({ format: "simple" });
|
||||
logger.info("User %s has %d points", "bob", 200);
|
||||
|
||||
assertMatch(capturedOutput, /User bob has 200 points/);
|
||||
} finally {
|
||||
@@ -292,16 +292,16 @@ Deno.test("Logger util.format functionality - Simple format output - should form
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Simple format output - should handle JSON formatting in simple format", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'simple' });
|
||||
const data = { status: 'active', count: 5 };
|
||||
logger.warn('Status: %j', data);
|
||||
const logger = new Logger({ format: "simple" });
|
||||
const data = { status: "active", count: 5 };
|
||||
logger.warn("Status: %j", data);
|
||||
|
||||
assertMatch(capturedOutput, /Status: {"status":"active","count":5}/);
|
||||
} finally {
|
||||
@@ -310,44 +310,44 @@ Deno.test("Logger util.format functionality - Simple format output - should hand
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Error handling in util.format - should handle objects that throw during toString", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const logger = new Logger({ format: "json" });
|
||||
const problematicObj = {
|
||||
toString() {
|
||||
throw new Error('toString failed');
|
||||
throw new Error("toString failed");
|
||||
},
|
||||
};
|
||||
|
||||
// The logger might handle the error gracefully, so let's test the actual output
|
||||
logger.info('Object: %s', problematicObj);
|
||||
logger.info("Object: %s", problematicObj);
|
||||
|
||||
// Check that something was logged (the logger should handle the error)
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertEquals(typeof output.msg, 'string');
|
||||
assertEquals(typeof output.msg, "string");
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test("Logger util.format functionality - Error handling in util.format - should handle circular references with %j", () => {
|
||||
let capturedOutput = '';
|
||||
let capturedOutput = "";
|
||||
const originalLog = console.log;
|
||||
console.log = (message) => {
|
||||
capturedOutput = message;
|
||||
};
|
||||
|
||||
try {
|
||||
const logger = new Logger({ format: 'json' });
|
||||
const circular = { name: 'test' };
|
||||
const logger = new Logger({ format: "json" });
|
||||
const circular = { name: "test" };
|
||||
circular.self = circular;
|
||||
|
||||
logger.info('Circular: %j', circular);
|
||||
logger.info("Circular: %j", circular);
|
||||
|
||||
const output = JSON.parse(capturedOutput);
|
||||
assertMatch(output.msg, /Circular: \[Circular\]/);
|
||||
@@ -355,4 +355,3 @@ Deno.test("Logger util.format functionality - Error handling in util.format - sh
|
||||
console.log = originalLog;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user