diff options
| author | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2020-09-21 01:00:19 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2020-09-21 01:00:19 +0200 |
| commit | ae85c067634676251e812765c81adfdef8f85f9d (patch) | |
| tree | ea1557df2172aeb30a363afec6a2183f05469d22 /test | |
| parent | 58906d77975b35fe93569f8083b90140124f9c41 (diff) | |
Update the code.
Diffstat (limited to 'test')
| -rw-r--r-- | test/cologne.js | 203 | ||||
| -rw-r--r-- | test/cologne/formatter/simple.js | 73 | ||||
| -rw-r--r-- | test/cologne/formatter/token.js | 107 | ||||
| -rw-r--r-- | test/cologne/log_utilities.js | 69 | ||||
| -rw-r--r-- | test/cologne/logger/console.js | 110 | ||||
| -rw-r--r-- | test/cologne/logger/file.js | 103 | ||||
| -rw-r--r-- | test/formatters/simple.js | 72 | ||||
| -rw-r--r-- | test/formatters/token.js | 121 | ||||
| -rw-r--r-- | test/loggers/console.js | 123 | ||||
| -rw-r--r-- | test/loggers/file.js | 106 | ||||
| -rw-r--r-- | test/utilities.js | 106 |
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'); |