This commit is contained in:
IanKulin
2025-09-25 21:26:31 +08:00
parent b95d3ea50a
commit 01cc58aa7a
14 changed files with 924 additions and 824 deletions

View File

@@ -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);
});
});