aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/cologne.js203
-rw-r--r--test/cologne/formatter/simple.js73
-rw-r--r--test/cologne/formatter/token.js107
-rw-r--r--test/cologne/log_utilities.js69
-rw-r--r--test/cologne/logger/console.js110
-rw-r--r--test/cologne/logger/file.js103
-rw-r--r--test/formatters/simple.js72
-rw-r--r--test/formatters/token.js121
-rw-r--r--test/loggers/console.js123
-rw-r--r--test/loggers/file.js106
-rw-r--r--test/utilities.js106
11 files changed, 612 insertions, 581 deletions
diff --git a/test/cologne.js b/test/cologne.js
index f5a6c6e..3f06763 100644
--- a/test/cologne.js
+++ b/test/cologne.js
@@ -1,186 +1,151 @@
'use strict';
-let tap = require('tap');
+const Tap = require('tap');
-let Cologne = require('../lib/cologne');
+const { Cologne } = require('..');
-let dummyLogger = {
- values : null,
- log : function () {
- let logObject;
+// Utility Functions
- this.values = [];
+const createDummyLogger = function () {
- for (logObject of arguments) {
- this.values.push(logObject);
+ return {
+ values: null,
+ log(...logs) {
+
+ this.values = [];
+
+ for (const log of logs) {
+ this.values.push(log);
+ }
}
- }
+ };
+};
+
+const levelChecker = function (level) {
+
+ return (count, log) => (log._level === level ? ++count : count);
};
+
// Prepare the test
-let dummyLoggerA, dummyLoggerB, dummyLoggerC,
- co, params, builtLog, meta,
- valueCheck, levelCheck;
-tap.plan(18);
+Tap.plan(19);
-dummyLoggerA = Object.assign({}, dummyLogger);
-dummyLoggerB = Object.assign({}, dummyLogger);
-dummyLoggerC = Object.assign({}, dummyLogger);
+const dummyLoggerA = createDummyLogger();
+const dummyLoggerB = createDummyLogger();
+const dummyLoggerC = createDummyLogger();
-co = new Cologne({
- loggers : [
+const co = new Cologne({
+ loggers: [
dummyLoggerA,
dummyLoggerB
]
});
-meta = {
- rainbows: true
-};
-
-params = ['example1', null, undefined, 1, {example: true}];
+const logs = ['example1', null, undefined, 1, { example: true }];
/**
* TEST: #log()
*/
-co.log.apply(co, params);
+co.log(...logs);
// Calculate values
-valueCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (typeof current._cologneLog === 'string') {
- previous++;
- }
- return previous;
-}, 0);
-levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (current._level === 6) {
- previous++;
- }
- return previous;
-}, 0);
+const valueCheck = dummyLoggerA.values.reduce((count, log) => (typeof log._cologneLog === 'string' ? ++count : count), 0);
+let levelCheck = dummyLoggerA.values.reduce(levelChecker(6), 0);
// Now check the values
-tap.equal(dummyLoggerA.values.length, params.length,
- '#log() should send every argument to the loggers');
+Tap.equal(dummyLoggerA.values.length, logs.length,
+ '#log() should send every argument to the loggers');
-tap.similar(dummyLoggerA.values, dummyLoggerB.values,
- '#log() should send the same arguments to all the loggers');
+Tap.similar(dummyLoggerA.values, dummyLoggerB.values,
+ '#log() should send the same arguments to all the loggers');
-tap.equal(valueCheck, params.length,
- '#log() should send all objects in cologne log format');
+Tap.equal(valueCheck, logs.length,
+ '#log() should send all objects in cologne log format');
-tap.equal(levelCheck, params.length,
- '#log() should default to level 6');
+Tap.equal(levelCheck, logs.length,
+ '#log() should default to level 6');
/**
* TEST: #debug()
*/
-co.debug.apply(co, params);
-levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (current._level === 7) {
- previous++;
- }
- return previous;
-}, 0);
+co.debug(...logs);
+levelCheck = dummyLoggerA.values.reduce(levelChecker(7), 0);
-tap.equal(levelCheck, params.length,
- '#debug() should set to level 7');
+Tap.equal(levelCheck, logs.length,
+ '#debug() should set to level 7');
/**
* TEST: #info()
*/
-co.info.apply(co, params);
-levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (current._level === 6) {
- previous++;
- }
- return previous;
-}, 0);
+co.info(...logs);
+levelCheck = dummyLoggerA.values.reduce(levelChecker(6), 0);
-tap.equal(levelCheck, params.length,
- '#info() should set to level 6');
+Tap.equal(levelCheck, logs.length,
+ '#info() should set to level 6');
/**
* TEST: #notice()
*/
-co.notice.apply(co, params);
-levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (current._level === 5) {
- previous++;
- }
- return previous;
-}, 0);
+co.notice(...logs);
+levelCheck = dummyLoggerA.values.reduce(levelChecker(5), 0);
-tap.equal(levelCheck, params.length,
- '#notice() should set to level 5');
+Tap.equal(levelCheck, logs.length,
+ '#notice() should set to level 5');
/**
* TEST: #warn()
*/
-co.warn.apply(co, params);
-levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (current._level === 4) {
- previous++;
- }
- return previous;
-}, 0);
+co.warn(...logs);
+levelCheck = dummyLoggerA.values.reduce(levelChecker(4), 0);
-tap.equal(levelCheck, params.length,
- '#warn() should set to level 4');
+Tap.equal(levelCheck, logs.length,
+ '#warn() should set to level 4');
/**
* TEST: #error()
*/
-co.error.apply(co, params);
-levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (current._level === 3) {
- previous++;
- }
- return previous;
-}, 0);
+co.error(...logs);
+levelCheck = dummyLoggerA.values.reduce(levelChecker(3), 0);
-tap.equal(levelCheck, params.length,
- '#error() should set to level 3');
+Tap.equal(levelCheck, logs.length,
+ '#error() should set to level 3');
/**
* TEST: #buildLog()
*/
-builtLog = co.buildLog('example');
+let builtLog = co.buildLog('example');
// With the default level
-tap.equal(typeof builtLog._cologneLog, 'string',
- '#buildLog() should return a cologne log');
-tap.equal(builtLog._level, 6,
- '#buildLog() should default to level 6');
+Tap.equal(typeof builtLog._cologneLog, 'string',
+ '#buildLog() should return a cologne log');
+Tap.equal(builtLog._level, 6,
+ '#buildLog() should default to level 6');
// Now with a specific value
builtLog = co.buildLog('example', 1);
-tap.equal(builtLog._level, 1,
- '#buildLog() should use the specified level');
+Tap.equal(builtLog._level, 1,
+ '#buildLog() should use the specified level');
-// Now with meta
-builtLog = co.buildLog('example', 1, meta);
+// Extending object properties
+builtLog = co.buildLog({ message: 'example', rainbows: true }, 1);
-tap.equal(builtLog.rainbows, true,
- '#buildLog() should extend the object with meta if available');
+Tap.equal(builtLog.message, 'example',
+ '#buildLog() should use the message property as the message if available');
+Tap.equal(builtLog.rainbows, true,
+ '#buildLog() should extend the object with its properties');
/**
* TEST: #log() with builtLog.
*/
co.log(builtLog);
-levelCheck = dummyLoggerA.values.reduce(function (previous, current) {
- if (current._level === 1) {
- previous++;
- }
- return previous;
-}, 0);
+levelCheck = dummyLoggerA.values.reduce(levelChecker(1), 0);
-tap.equal(levelCheck, 1,
- '#log() calls using a pre-built cologne log should maintain the log level');
+Tap.equal(levelCheck, 1,
+ '#log() calls using a pre-built cologne log should maintain the log level');
/**
@@ -188,25 +153,25 @@ tap.equal(levelCheck, 1,
*/
co.removeLogger(dummyLoggerC);
-tap.equal(co.loggers.length, 2,
- '#removeLogger() should do nothing if it can\'t find a logger');
+Tap.equal(co.loggers.length, 2,
+ '#removeLogger() should do nothing if it can\'t find a logger');
-co.log.apply(co, params);
+co.log(...logs);
co.removeLogger(dummyLoggerB);
co.log(1);
-tap.equal(co.loggers.length, 1,
- '#removeLogger() should remove a logger');
+Tap.equal(co.loggers.length, 1,
+ '#removeLogger() should remove a logger');
-tap.notEqual(dummyLoggerB.values.length, dummyLoggerA.values.length,
- '#removeLogger() should no longer affect removed logs');
+Tap.notEqual(dummyLoggerB.values.length, dummyLoggerA.values.length,
+ '#removeLogger() should no longer affect removed logs');
/**
* TEST: #addLogger()
*/
co.addLogger(dummyLoggerC);
-co.log.apply(co, params);
+co.log(...logs);
-tap.equal(dummyLoggerC.values.length, params.length,
- '#addLogger() should add loggers after instance is live');
+Tap.equal(dummyLoggerC.values.length, logs.length,
+ '#addLogger() should add loggers after instance is live');
diff --git a/test/cologne/formatter/simple.js b/test/cologne/formatter/simple.js
deleted file mode 100644
index 8642541..0000000
--- a/test/cologne/formatter/simple.js
+++ /dev/null
@@ -1,73 +0,0 @@
-'use strict';
-
-let tap = require('tap');
-
-let SimpleFormatter = require('../../../lib/cologne/formatter/simple');
-
-// Prepare the test
-let logObject, colorFormatter, plainFormatter, formattedString, isoDate;
-
-tap.plan(12);
-
-logObject = {
- _timestamp: Date.now() + .134,
- _cologneLog: '1.0.0',
- _from: 'Dummy Logger',
- _level: 3,
- _levelString: 'error',
- message: 'testing stuff!'
-};
-isoDate = (new Date(logObject._timestamp)).toISOString();
-
-plainFormatter = new SimpleFormatter();
-colorFormatter = new SimpleFormatter({
- colorize: true
-});
-
-/**
- * TEST: #format() - plain
- */
-
-formattedString = plainFormatter.format(logObject);
-
-tap.equal(typeof formattedString, 'string',
- '#format() should output a string in plain mode');
-
-tap.ok(formattedString.match(logObject._from),
- '#format() should include the from property in plain mode');
-
-tap.ok(formattedString.match(isoDate),
- '#format() should include the timestamp property in iso format in plain mode');
-
-tap.ok(formattedString.match(logObject._levelString),
- '#format() should include the level string property in plain mode');
-
-tap.ok(formattedString.match(logObject.message),
- '#format() should include the message property in plain mode');
-
-/**
- * TEST: #format() - colorized
- */
-
-formattedString = colorFormatter.format(logObject);
-
-tap.equal(typeof formattedString, 'string',
- '#format() should output a string in color mode');
-
-tap.ok(formattedString.match(logObject._from),
- '#format() should include the from property in color mode');
-
-tap.ok(formattedString.match(isoDate),
- '#format() should include the timestamp property in iso format in color mode');
-
-tap.ok(formattedString.match(logObject._levelString),
- '#format() should include the level string property in color mode');
-
-tap.ok(formattedString.match(logObject.message),
- '#format() should include the message property in color mode');
-
-tap.equal(formattedString.split(String.fromCharCode(27) + '[31m').length, 2,
- '#format() should colorize the string');
-
-tap.equal(formattedString.split(String.fromCharCode(27) + '[0m').length, 2,
- '#format() should colorize only a bit of the string');
diff --git a/test/cologne/formatter/token.js b/test/cologne/formatter/token.js
deleted file mode 100644
index 9bc473d..0000000
--- a/test/cologne/formatter/token.js
+++ /dev/null
@@ -1,107 +0,0 @@
-'use strict';
-
-let tap = require('tap');
-
-let TokenFormatter = require('../../../lib/cologne/formatter/token');
-
-// Prepare the test
-let logObject, defaultFormatter, customFormatter, ansiFormatter,
- plainDateFormatter, customSearchFormatter, formattedString, isoDate;
-
-tap.plan(13);
-
-logObject = {
- _timestamp: Date.now() + .134,
- _cologneLog: '1.0.0',
- _from: 'Dummy Logger',
- _level: 3,
- _levelString: 'error',
- message: 'testing stuff!'
-};
-isoDate = (new Date(logObject._timestamp)).toISOString();
-
-defaultFormatter = new TokenFormatter();
-customFormatter = new TokenFormatter({
- formatString: '{{_level}} {{_cologneLog}} {{_timestamp}}'
-});
-ansiFormatter = new TokenFormatter({
- formatString: 'string {{_ansi:red}}with color:{{_ansi:reset}} {{message}}'
-});
-plainDateFormatter = new TokenFormatter({
- isoDate: false,
- formatString: '{{_timestamp}}'
-});
-customSearchFormatter = new TokenFormatter({
- formatString: '[[message]]',
- replaceRule: /\[\[(.*?)\]\]/g
-});
-
-/**
- * TEST: #format() - default
- */
-
-formattedString = defaultFormatter.format(logObject);
-
-tap.equal(typeof formattedString, 'string',
- '#format() should output a string in default mode');
-
-tap.equal(formattedString, logObject.message,
- '#format() should include the message in default mode');
-
-/**
- * TEST: #format() - custom
- */
-
-formattedString = customFormatter.format(logObject);
-
-tap.equal(typeof formattedString, 'string',
- '#format() should output a string in custom mode');
-
-tap.ok(formattedString.match(logObject._level),
- '#format() with custom string should include the specified tokens (check 1)');
-
-tap.ok(formattedString.match(logObject._cologneLog),
- '#format() with custom string should include the specified tokens (check 2)');
-
-tap.ok(formattedString.match(isoDate),
- '#format() with iso date should include the timestamp as an iso date');
-
-/**
- * TEST: #format() - ansi
- */
-
-formattedString = ansiFormatter.format(logObject);
-
-tap.equal(typeof formattedString, 'string',
- '#format() should output a string in ansi mode');
-
-tap.equal(formattedString.split(String.fromCharCode(27) + '[31m').length, 2,
- '#format() with ansi tokens should colorize the string');
-
-tap.equal(formattedString.split(String.fromCharCode(27) + '[0m').length, 2,
- '#format() with ansi reset should reset the string');
-
-
-/**
- * TEST: #format() - plain date
- */
-
-formattedString = plainDateFormatter.format(logObject);
-
-tap.equal(typeof formattedString, 'string',
- '#format() should output a string in plain date mode');
-
-tap.equal(formattedString, logObject._timestamp.toString(),
- '#format() with plain date should include the timestamp as-is');
-
-/**
- * TEST: #format() - custom search
- */
-
-formattedString = customSearchFormatter.format(logObject);
-
-tap.equal(typeof formattedString, 'string',
- '#format() should output a string in custom search mode');
-
-tap.equal(formattedString, logObject.message,
- '#format() with a custom search, should properly match the new tokens');
diff --git a/test/cologne/log_utilities.js b/test/cologne/log_utilities.js
deleted file mode 100644
index e372683..0000000
--- a/test/cologne/log_utilities.js
+++ /dev/null
@@ -1,69 +0,0 @@
-'use strict';
-
-let tap = require('tap');
-
-let LogUtilities = require('../../lib/cologne/log_utilities');
-
-// Prepare the test
-let t1, t2, preciseTime, regularObject, circularObject,
- regularStringify, cologneStringify, circularStringify;
-
-tap.plan(7);
-
-regularObject = {
- a: 1,
- b: {
- c: 'true',
- d: false
- }
-};
-
-circularObject = {
- a: 1,
- b: {
- c: 'true',
- d: false
- }
-};
-circularObject.b.circular = circularObject;
-
-/**
- * TEST: ::now()
- */
-t1 = Date.now();
-preciseTime = LogUtilities.now();
-t2 = Date.now();
-
-// This test is sloppy :(
-tap.ok(Math.abs(t1 - preciseTime) < 1,
- '::now() should give a precise timestamp (before)');
-tap.ok(Math.abs(t2 - preciseTime) < 1,
- '::now() should give a precise timestamp (after)');
-
-/**
- * TEST: ::stringify()
- */
-
-regularStringify = JSON.stringify(regularObject);
-cologneStringify = LogUtilities.stringify(regularObject);
-circularStringify = LogUtilities.stringify(circularObject);
-
-tap.equal(regularStringify, cologneStringify,
- '::stringify() should behave like JSON.stringify for non-circular objects');
-tap.equal(typeof JSON.parse(circularStringify).b.circular, 'string',
- '::stringify() should replace circular references with a string');
-
-/**
- * TEST: ::getAnsiCode()
- */
-
-// NOTE: This isn't even trying to be a complete test... Just testing
-// that we get other than reset if valid, and the same as reset for all
-// invalid ones. knowing that reset is [0m
-
-tap.equal(LogUtilities.getAnsiCode('reset'), '[0m',
- '::getAnsiCode is sending the correct reset code');
-tap.equal(LogUtilities.getAnsiCode('someRandomString'), LogUtilities.getAnsiCode('reset'),
- '::getAnsiCode() should give us a reset code if something weird is sent');
-tap.notEqual(LogUtilities.getAnsiCode('red'), LogUtilities.getAnsiCode('reset'),
- '::getAnsiCode() should give us a non-reset code if it\'s something real');
diff --git a/test/cologne/logger/console.js b/test/cologne/logger/console.js
deleted file mode 100644
index ffc1876..0000000
--- a/test/cologne/logger/console.js
+++ /dev/null
@@ -1,110 +0,0 @@
-'use strict';
-
-let tap = require('tap');
-
-let ConsoleLogger = require('../../../lib/cologne/logger/console');
-
-// Prepare the test
-let dummyFormatter, dummyConsole, logObjectA, logObjectB, regularLogger,
- overrideLogger, formattedLogger, params;
-
-dummyFormatter = {
- values: [],
- format: function (logObject) {
- this.values.push(logObject);
- return 'lol';
- }
-};
-
-dummyConsole = {
- values: {},
- _log: function (type, args) {
- this.values[type] = args;
- },
- log: function() {
- this._log('log', Array.prototype.splice.call(arguments, [0]));
- },
- warn: function() {
- this._log('warn', Array.prototype.splice.call(arguments, [0]));
- },
- error: function() {
- this._log('error', Array.prototype.splice.call(arguments, [0]));
- },
- info: function() {
- this._log('info', Array.prototype.splice.call(arguments, [0]));
- }
-};
-
-logObjectA = {
- _timestamp: Date.now() + .134,
- _cologneLog: '1.0.0',
- _from: 'Dummy Logger',
- _level: 6,
- _levelString: 'info',
- message: 'MessageOne'
-};
-
-logObjectB = {
- _timestamp: Date.now() + .134,
- _cologneLog: '1.0.0',
- _from: 'Dummy Logger',
- _level: 6,
- _levelString: 'info',
- message: 'MessageTwo'
-};
-
-params = [logObjectA, logObjectB];
-
-regularLogger = new ConsoleLogger({});
-overrideLogger = new ConsoleLogger({
- console: dummyConsole
-});
-formattedLogger = new ConsoleLogger({
- console: dummyConsole,
- formatter: dummyFormatter
-});
-
-/**
- * TEST: #log() - regular
- */
-
-tap.equal(regularLogger.console, global.console,
- 'It should default to the global console');
-
-/**
- * TEST: #log() - override
- */
-
-logObjectA._level = 5;
-logObjectB._level = 6;
-overrideLogger.log.apply(overrideLogger, params); // should go to info
-
-logObjectA._level = 4;
-logObjectB._level = 4;
-overrideLogger.log.apply(overrideLogger, params); // should go to warn
-
-logObjectA._level = 1;
-logObjectB._level = 3;
-overrideLogger.log.apply(overrideLogger, params); // should go to error
-
-logObjectA._level = 7;
-logObjectB._level = 7;
-overrideLogger.log.apply(overrideLogger, params); // should go to log
-
-tap.equal(dummyConsole.values.log.length, params.length,
- 'It should send debug messages to console\'s #log');
-tap.equal(dummyConsole.values.info.length, params.length,
- 'It should send info and notice messages to console\'s #info');
-tap.equal(dummyConsole.values.warn.length, params.length,
- 'It should send warn messages to console\'s #warn');
-tap.equal(dummyConsole.values.error.length, params.length,
- 'It should send error messages to console\'s #error');
-
-/**
- * TEST: #log() - with formatter
- */
-
-formattedLogger.log.apply(formattedLogger, params); // should go to log
-
-tap.similar(dummyFormatter.values, params,
- 'If available, it should send the objects to the formatter');
diff --git a/test/cologne/logger/file.js b/test/cologne/logger/file.js
deleted file mode 100644
index 01be09f..0000000
--- a/test/cologne/logger/file.js
+++ /dev/null
@@ -1,103 +0,0 @@
-'use strict';
-
-let fs = require('fs');
-
-let tap = require('tap');
-
-let FileLogger = require('../../../lib/cologne/logger/file');
-
-// Prepare the test
-let logObjectA, logObjectB, rawFile, formatterFile, rawLogger, formatterLogger,
- params, dummyFormatter, formatterString;
-
-rawFile = './raw.log';
-formatterFile = './formatter.log';
-formatterString = 'example';
-
-logObjectA = {
- _timestamp: Date.now() + .134,
- _cologneLog: '1.0.0',
- _from: 'Dummy Logger',
- _level: 6,
- _levelString: 'info',
- message: 'MessageOne'
-};
-
-logObjectB = {
- _timestamp: Date.now() + .134,
- _cologneLog: '1.0.0',
- _from: 'Dummy Logger',
- _level: 6,
- _levelString: 'info',
- message: 'MessageTwo'
-};
-
-params = [logObjectA, logObjectB];
-
-
-dummyFormatter = {
- values: [],
- format: function (logObject) {
- this.values.push(logObject);
- return formatterString;
- }
-};
-
-rawLogger = new FileLogger({
- file: rawFile
-});
-formatterLogger = new FileLogger({
- file: formatterFile,
- formatter: dummyFormatter
-});
-
-/**
- * TEST: #log() - regular
- */
-
-rawLogger.log.apply(rawLogger, params);
-
-setTimeout(function () {
- tap.test('raw file', function (t) {
- fs.readFile(rawFile, {encoding: 'utf8'}, function (error, contents) {
- let lines;
-
- lines = contents.trim().split('\n');
-
- tap.equal(lines.length, params.length,
- 'it should send all params to the file');
-
- tap.equal(JSON.stringify(logObjectA), lines[0],
- 'it should log the raw json object');
-
- fs.unlink(rawFile, function () {
- t.end();
- });
- });
- });
-}, 10); // allow for flush
-/**
- * TEST: #log() - formatter
- */
-
-formatterLogger.log.apply(formatterLogger, params);
-
-setTimeout(function () {
- tap.test('formatted file', function (t) {
- fs.readFile(formatterFile, {encoding: 'utf8'}, function (error, contents) {
- let lines;
-
- lines = contents.trim().split('\n');
-
- tap.equal(lines.length, params.length,
- 'it should send all params to the file');
-
- tap.equal(formatterString, lines[0],
- 'it should log the formatted object');
-
- fs.unlink(formatterFile, function () {
- t.end();
- });
- });
- });
-}, 10);
diff --git a/test/formatters/simple.js b/test/formatters/simple.js
new file mode 100644
index 0000000..5829045
--- /dev/null
+++ b/test/formatters/simple.js
@@ -0,0 +1,72 @@
+'use strict';
+
+const Tap = require('tap');
+
+const SimpleFormatter = require('../../lib/formatters/simple');
+
+// Prepare the test
+
+Tap.plan(12);
+
+const logObject = {
+ _timestamp: BigInt(Date.now()) * 1000000n,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 3,
+ _levelString: 'error',
+ message: 'testing stuff!'
+};
+const isoDate = (new Date(Number(logObject._timestamp) / 1000000)).toISOString();
+
+const plainFormatter = new SimpleFormatter();
+const colorFormatter = new SimpleFormatter({
+ colorize: true
+});
+
+/**
+ * TEST: #format() - plain
+ */
+
+const plainFormattedString = plainFormatter.format(logObject);
+
+Tap.equal(typeof plainFormattedString, 'string',
+ '#format() should output a string in plain mode');
+
+Tap.ok(plainFormattedString.match(logObject._from),
+ '#format() should include the from property in plain mode');
+
+Tap.ok(plainFormattedString.match(isoDate),
+ '#format() should include the timestamp property in iso format in plain mode');
+
+Tap.ok(plainFormattedString.match(logObject._levelString),
+ '#format() should include the level string property in plain mode');
+
+Tap.ok(plainFormattedString.match(logObject.message),
+ '#format() should include the message property in plain mode');
+
+/**
+ * TEST: #format() - colorized
+ */
+
+const colorFormattedString = colorFormatter.format(logObject);
+
+Tap.equal(typeof colorFormattedString, 'string',
+ '#format() should output a string in color mode');
+
+Tap.ok(colorFormattedString.match(logObject._from),
+ '#format() should include the from property in color mode');
+
+Tap.ok(colorFormattedString.match(isoDate),
+ '#format() should include the timestamp property in iso format in color mode');
+
+Tap.ok(colorFormattedString.match(logObject._levelString),
+ '#format() should include the level string property in color mode');
+
+Tap.ok(colorFormattedString.match(logObject.message),
+ '#format() should include the message property in color mode');
+
+Tap.equal(colorFormattedString.split(String.fromCharCode(27) + '[31m').length, 2,
+ '#format() should colorize the string');
+
+Tap.equal(colorFormattedString.split(String.fromCharCode(27) + '[0m').length, 2,
+ '#format() should colorize only a bit of the string');
diff --git a/test/formatters/token.js b/test/formatters/token.js
new file mode 100644
index 0000000..e9baefd
--- /dev/null
+++ b/test/formatters/token.js
@@ -0,0 +1,121 @@
+'use strict';
+
+const Tap = require('tap');
+
+const TokenFormatter = require('../../lib/formatters/token');
+
+// Prepare the test
+
+Tap.plan(15);
+
+const logObject = {
+ _timestamp: BigInt(Date.now()) * 1000000n,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'error',
+ message: 'testing stuff!'
+};
+const isoDate = (new Date(Number(logObject._timestamp) / 1000000)).toISOString();
+
+const defaultFormatter = new TokenFormatter();
+const customFormatter = new TokenFormatter({
+ formatString: '{{_level}} {{_cologneLog}} {{_timestamp}} {{_magic}}'
+});
+const ansiFormatter = new TokenFormatter({
+ formatString: 'string {{_ansi:red}}with color:{{_ansi:reset}} {{message}}'
+});
+const ansiLevelFormatter = new TokenFormatter({
+ formatString: 'string {{_ansi:_level}}with color:{{_ansi:reset}} {{message}}'
+});
+const plainDateFormatter = new TokenFormatter({
+ isoDate: false,
+ formatString: '{{_timestamp}}'
+});
+const customSearchFormatter = new TokenFormatter({
+ formatString: '[[message]]',
+ replaceRule: /\[\[(.*?)\]\]/g
+});
+
+/**
+ * TEST: #format() - default
+ */
+
+const defaultFormattedString = defaultFormatter.format(logObject);
+
+Tap.equal(typeof defaultFormattedString, 'string',
+ '#format() should output a string in default mode');
+
+Tap.equal(defaultFormattedString, logObject.message,
+ '#format() should include the message in default mode');
+
+/**
+ * TEST: #format() - custom
+ */
+
+const customFormattedString = customFormatter.format(logObject);
+
+Tap.equal(typeof customFormattedString, 'string',
+ '#format() should output a string in custom mode');
+
+Tap.ok(customFormattedString.match(logObject._level),
+ '#format() with custom string should include the specified tokens (check 1)');
+
+Tap.ok(customFormattedString.match(logObject._cologneLog),
+ '#format() with custom string should include the specified tokens (check 2)');
+
+Tap.ok(customFormattedString.match(isoDate),
+ '#format() with iso date should include the timestamp as an iso date');
+
+Tap.ok(customFormattedString.match('{{_magic}}'),
+ '#format() should not replace tokens that don\'t match');
+
+/**
+ * TEST: #format() - ansi
+ */
+
+const ansiFormattedString = ansiFormatter.format(logObject);
+
+Tap.equal(typeof ansiFormattedString, 'string',
+ '#format() should output a string in ansi mode');
+
+Tap.equal(ansiFormattedString.split(String.fromCharCode(27) + '[31m').length, 2,
+ '#format() with ansi tokens should colorize the string');
+
+Tap.equal(ansiFormattedString.split(String.fromCharCode(27) + '[0m').length, 2,
+ '#format() with ansi reset should reset the string');
+
+/**
+ * TEST: #format() - ansi based on level
+ */
+
+const ansiLevelFormattedString = ansiLevelFormatter.format(logObject);
+
+Tap.equal(ansiLevelFormattedString.split(String.fromCharCode(27) + '[34m').length, 2,
+ '#format() with ansi tokens should colorize the string based on level');
+
+
+
+/**
+ * TEST: #format() - plain date
+ */
+
+const plainDateFormattedString = plainDateFormatter.format(logObject);
+
+Tap.equal(typeof plainDateFormattedString, 'string',
+ '#format() should output a string in plain date mode');
+
+Tap.equal(plainDateFormattedString, logObject._timestamp.toString(),
+ '#format() with plain date should include the timestamp as-is');
+
+/**
+ * TEST: #format() - custom search
+ */
+
+const customSearchFormattedString = customSearchFormatter.format(logObject);
+
+Tap.equal(typeof customSearchFormattedString, 'string',
+ '#format() should output a string in custom search mode');
+
+Tap.equal(customSearchFormattedString, logObject.message,
+ '#format() with a custom search, should properly match the new tokens');
diff --git a/test/loggers/console.js b/test/loggers/console.js
new file mode 100644
index 0000000..3358837
--- /dev/null
+++ b/test/loggers/console.js
@@ -0,0 +1,123 @@
+'use strict';
+
+const Tap = require('tap');
+
+const ConsoleLogger = require('../../lib/loggers/console');
+
+// Prepare the test
+
+const dummyFormatter = {
+ values: [],
+ format: function (log) {
+
+ this.values.push(log);
+ return 'lol';
+ }
+};
+
+const dummyConsole = {
+ values: {
+ log: 0,
+ warn: 0,
+ error: 0,
+ info: 0
+ },
+ _log: function (type, ...logs) {
+
+ this.values[type] += logs.length;
+ },
+ log: function (...logs) {
+
+ this._log('log', ...logs);
+ },
+ warn: function (...logs) {
+
+ this._log('warn', ...logs);
+ },
+ error: function (...logs) {
+
+ this._log('error', ...logs);
+ },
+ info: function (...logs) {
+
+ this._log('info', ...logs);
+ }
+};
+
+const logObjectA = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageOne'
+};
+
+const logObjectB = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageTwo'
+};
+
+const logs = [logObjectA, logObjectB];
+
+const regularLogger = new ConsoleLogger({});
+const overrideLogger = new ConsoleLogger({
+ console: dummyConsole
+});
+const formattedLogger = new ConsoleLogger({
+ console: dummyConsole,
+ formatter: dummyFormatter
+});
+
+/**
+ * TEST: #log() - regular
+ */
+
+Tap.equal(regularLogger.console, global.console,
+ 'It should default to the global console');
+
+/**
+ * TEST: #log() - override
+ */
+
+logObjectA._level = 5;
+logObjectB._level = 6;
+overrideLogger.log(...logs); // should go to info
+
+logObjectA._level = 4;
+logObjectB._level = 4;
+overrideLogger.log(...logs); // should go to warn
+
+logObjectA._level = 1;
+logObjectB._level = 3;
+overrideLogger.log(...logs); // should go to error
+
+logObjectA._level = 0;
+logObjectB._level = 2;
+overrideLogger.log(...logs); // should go to error
+
+logObjectA._level = 7;
+logObjectB._level = 8;
+overrideLogger.log(...logs); // should go to log
+
+Tap.equal(dummyConsole.values.log, logs.length,
+ 'It should send debug messages to console\'s #log');
+Tap.equal(dummyConsole.values.info, logs.length,
+ 'It should send info and notice messages to console\'s #info');
+Tap.equal(dummyConsole.values.warn, logs.length,
+ 'It should send warn messages to console\'s #warn');
+Tap.equal(dummyConsole.values.error, logs.length * 2,
+ 'It should send error messages to console\'s #error');
+
+/**
+ * TEST: #log() - with formatter
+ */
+
+formattedLogger.log(...logs); // should go to log
+
+Tap.similar(dummyFormatter.values, logs,
+ 'If available, it should send the objects to the formatter');
diff --git a/test/loggers/file.js b/test/loggers/file.js
new file mode 100644
index 0000000..5e73d82
--- /dev/null
+++ b/test/loggers/file.js
@@ -0,0 +1,106 @@
+'use strict';
+
+const Fs = require('fs');
+
+const Tap = require('tap');
+
+const FileLogger = require('../../lib/loggers/file');
+
+// Prepare the test
+
+const rawFile = './raw.log';
+const formatterFile = './formatter.log';
+const formatterString = 'example';
+
+const logObjectA = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageOne'
+};
+
+const logObjectB = {
+ _timestamp: Date.now() + .134,
+ _cologneLog: '1.0.0',
+ _from: 'Dummy Logger',
+ _level: 6,
+ _levelString: 'info',
+ message: 'MessageTwo'
+};
+
+const logs = [logObjectA, logObjectB];
+
+
+const dummyFormatter = {
+ values: [],
+ format: function (logObject) {
+
+ this.values.push(logObject);
+ return formatterString;
+ }
+};
+
+const rawLogger = new FileLogger({
+ file: rawFile
+});
+const formatterLogger = new FileLogger({
+ file: formatterFile,
+ formatter: dummyFormatter
+});
+
+/**
+ * TEST: #log() - regular
+ */
+
+rawLogger.log(...logs);
+
+setTimeout(() => {
+
+ Tap.test('raw file', (t) => {
+
+ Fs.readFile(rawFile, { encoding: 'utf8' }, (_, contents) => {
+
+ const lines = contents.trim().split('\n');
+
+ Tap.equal(lines.length, logs.length,
+ 'it should send all params to the file');
+
+ Tap.equal(JSON.stringify(logObjectA), lines[0],
+ 'it should log the raw json object');
+
+ Fs.unlink(rawFile, () => {
+
+ t.end();
+ });
+ });
+ });
+}, 10); // allow for flush
+/**
+ * TEST: #log() - formatter
+ */
+
+formatterLogger.log(...logs);
+
+setTimeout(() => {
+
+ Tap.test('formatted file', (t) => {
+
+ Fs.readFile(formatterFile, { encoding: 'utf8' }, (_, contents) => {
+
+ const lines = contents.trim().split('\n');
+
+ Tap.equal(lines.length, logs.length,
+ 'it should send all params to the file');
+
+ Tap.equal(formatterString, lines[0],
+ 'it should log the formatted object');
+
+ Fs.unlink(formatterFile, () => {
+
+ t.end();
+ });
+ });
+ });
+}, 10);
diff --git a/test/utilities.js b/test/utilities.js
new file mode 100644
index 0000000..2bff47f
--- /dev/null
+++ b/test/utilities.js
@@ -0,0 +1,106 @@
+'use strict';
+
+const Tap = require('tap');
+
+const Utilities = require('../lib/utilities');
+
+// Prepare the test
+
+Tap.plan(17);
+
+/**
+ * TEST: ::now()
+ */
+const preciseTime = Utilities.now();
+
+// I don't think this test makes sense lol
+Tap.equal(typeof preciseTime, 'bigint',
+ '::now() should give a precise bigint timestamp');
+
+/**
+ * TEST: ::stringify()
+ */
+
+const regularObject = {
+ a: 1,
+ b: {
+ c: 'true',
+ d: false
+ }
+};
+
+const circularObject = {
+ a: 1,
+ b: {
+ c: 'true',
+ d: false
+ }
+};
+circularObject.b.circular = circularObject;
+
+const bigint = 666n;
+
+const regularStringify = JSON.stringify(regularObject);
+const cologneStringify = Utilities.stringify(regularObject);
+const circularStringify = Utilities.stringify(circularObject);
+const bigintStringify = Utilities.stringify(bigint);
+
+Tap.equal(regularStringify, cologneStringify,
+ '::stringify() should behave like JSON.stringify for non-circular objects');
+Tap.equal(typeof JSON.parse(circularStringify).b.circular, 'string',
+ '::stringify() should replace circular references with a string');
+Tap.equal(bigintStringify, '"666n"',
+ '::stringify() should convert bigint to string');
+
+/**
+ * TEST: ::getAnsiCode()
+ */
+
+// NOTE: This isn't even trying to be a complete test... Just testing
+// that we get distinct non-reset codes if valid, and the same as reset
+// for all invalid ones. knowing that reset is [0m
+
+Tap.equal(Utilities.getAnsiCode('reset'), '[0m',
+ '::getAnsiCode is sending the correct reset code');
+Tap.equal(Utilities.getAnsiCode('someRandomString'), Utilities.getAnsiCode('reset'),
+ '::getAnsiCode() should give us a reset code if something weird is sent');
+
+const supportedCodes = ['bold', 'italics', 'underline', 'inverse', 'strikethrough',
+ 'bold_off', 'italics_off', 'underline_off', 'inverse_off', 'strikethrough_off',
+ 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default',
+ 'black_bg', 'red_bg', 'green_bg', 'yellow_bg', 'blue_bg', 'magenta_bg',
+ 'cyan_bg', 'white_bg', 'default_bg'];
+const resultingCodes = supportedCodes.map((code) => Utilities.getAnsiCode(code));
+const isThereReset = resultingCodes.some((code) => code === '[0m');
+
+Tap.equal((new Set(resultingCodes)).size, supportedCodes.length,
+ '::getAnsiCode() should not have duplicated non-reset codes');
+Tap.false(isThereReset,
+ '::getAnsiCode() should not return a reset code in any other supported code');
+
+/**
+ * TEST: ::getLevelAnsi()
+ */
+
+// NOTE: This isn't even trying to be a complete test... Just testing
+// that we get other than reset if valid, and the same as reset for all
+// invalid ones. knowing that reset is [0m
+
+Tap.equal(Utilities.getLevelAnsi(0), 'red',
+ '::gettLevelAnsi is red for emerg');
+Tap.equal(Utilities.getLevelAnsi(1), 'red',
+ '::gettLevelAnsi is red for alert');
+Tap.equal(Utilities.getLevelAnsi(2), 'red',
+ '::gettLevelAnsi is red for crit');
+Tap.equal(Utilities.getLevelAnsi(3), 'red',
+ '::gettLevelAnsi is red for error');
+Tap.equal(Utilities.getLevelAnsi(4), 'yellow',
+ '::gettLevelAnsi is yellow for warn');
+Tap.equal(Utilities.getLevelAnsi(5), 'blue',
+ '::gettLevelAnsi is blue for notice');
+Tap.equal(Utilities.getLevelAnsi(6), 'blue',
+ '::gettLevelAnsi is blue for info');
+Tap.equal(Utilities.getLevelAnsi(7), 'green',
+ '::gettLevelAnsi is green for debug');
+Tap.equal(Utilities.getLevelAnsi(8), 'default',
+ '::gettLevelAnsi is default for other values');