11cb0ef41Sopenharmony_ciconst t = require('tap') 21cb0ef41Sopenharmony_ciconst log = require('../../../lib/utils/log-shim') 31cb0ef41Sopenharmony_ciconst mockLogs = require('../../fixtures/mock-logs') 41cb0ef41Sopenharmony_ciconst mockGlobals = require('@npmcli/mock-globals') 51cb0ef41Sopenharmony_ciconst tmock = require('../../fixtures/tmock') 61cb0ef41Sopenharmony_ciconst util = require('util') 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciconst mockDisplay = (t, mocks) => { 91cb0ef41Sopenharmony_ci const { logs, logMocks } = mockLogs(mocks) 101cb0ef41Sopenharmony_ci const Display = tmock(t, '{LIB}/utils/display', { 111cb0ef41Sopenharmony_ci ...mocks, 121cb0ef41Sopenharmony_ci ...logMocks, 131cb0ef41Sopenharmony_ci }) 141cb0ef41Sopenharmony_ci const display = new Display() 151cb0ef41Sopenharmony_ci t.teardown(() => display.off()) 161cb0ef41Sopenharmony_ci return { display, logs } 171cb0ef41Sopenharmony_ci} 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_cit.test('setup', async (t) => { 201cb0ef41Sopenharmony_ci const { display } = mockDisplay(t) 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci display.load({ timing: true, loglevel: 'notice' }) 231cb0ef41Sopenharmony_ci t.equal(log.level, 'notice') 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci display.load({ timing: false, loglevel: 'notice' }) 261cb0ef41Sopenharmony_ci t.equal(log.level, 'notice') 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci display.load({ color: true }) 291cb0ef41Sopenharmony_ci t.equal(log.useColor(), true) 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci display.load({ unicode: true }) 321cb0ef41Sopenharmony_ci t.equal(log.gauge._theme.hasUnicode, true) 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci display.load({ unicode: false }) 351cb0ef41Sopenharmony_ci t.equal(log.gauge._theme.hasUnicode, false) 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci mockGlobals(t, { 'process.stderr.isTTY': true }) 381cb0ef41Sopenharmony_ci display.load({ progress: true }) 391cb0ef41Sopenharmony_ci t.equal(log.progressEnabled, true) 401cb0ef41Sopenharmony_ci}) 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_cit.test('can log cleanly', async (t) => { 431cb0ef41Sopenharmony_ci const explains = [] 441cb0ef41Sopenharmony_ci const { display, logs } = mockDisplay(t, { 451cb0ef41Sopenharmony_ci npmlog: { 461cb0ef41Sopenharmony_ci error: (...args) => logs.push(['error', ...args]), 471cb0ef41Sopenharmony_ci warn: (...args) => logs.push(['warn', ...args]), 481cb0ef41Sopenharmony_ci }, 491cb0ef41Sopenharmony_ci '{LIB}/utils/explain-eresolve.js': { 501cb0ef41Sopenharmony_ci explain: (...args) => { 511cb0ef41Sopenharmony_ci explains.push(args) 521cb0ef41Sopenharmony_ci return 'explanation' 531cb0ef41Sopenharmony_ci }, 541cb0ef41Sopenharmony_ci }, 551cb0ef41Sopenharmony_ci }) 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci display.log('error', 'test\x00message') 581cb0ef41Sopenharmony_ci t.match(logs.error, [['test^@message']]) 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci display.log('warn', 'ERESOLVE', 'hello', { some: 'object' }) 611cb0ef41Sopenharmony_ci t.match(logs.warn, [['ERESOLVE', 'hello']]) 621cb0ef41Sopenharmony_ci t.match(explains, [[{ some: 'object' }, null, 2]]) 631cb0ef41Sopenharmony_ci}) 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_cit.test('handles log throwing', async (t) => { 661cb0ef41Sopenharmony_ci const errors = [] 671cb0ef41Sopenharmony_ci mockGlobals(t, { 681cb0ef41Sopenharmony_ci 'console.error': (...args) => errors.push(args), 691cb0ef41Sopenharmony_ci }) 701cb0ef41Sopenharmony_ci const { display } = mockDisplay(t, { 711cb0ef41Sopenharmony_ci npmlog: { 721cb0ef41Sopenharmony_ci verbose: () => { 731cb0ef41Sopenharmony_ci throw new Error('verbose') 741cb0ef41Sopenharmony_ci }, 751cb0ef41Sopenharmony_ci }, 761cb0ef41Sopenharmony_ci '{LIB}/utils/explain-eresolve.js': { 771cb0ef41Sopenharmony_ci explain: () => { 781cb0ef41Sopenharmony_ci throw new Error('explain') 791cb0ef41Sopenharmony_ci }, 801cb0ef41Sopenharmony_ci }, 811cb0ef41Sopenharmony_ci }) 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci display.log('warn', 'ERESOLVE', 'hello', { some: 'object' }) 841cb0ef41Sopenharmony_ci t.match(errors, [ 851cb0ef41Sopenharmony_ci [/attempt to log .* crashed/, Error('explain'), Error('verbose')], 861cb0ef41Sopenharmony_ci ]) 871cb0ef41Sopenharmony_ci}) 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ciclass CustomObj { 901cb0ef41Sopenharmony_ci [util.inspect.custom] () { 911cb0ef41Sopenharmony_ci return this.inspected 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci} 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_cit.test('Display.clean', async (t) => { 961cb0ef41Sopenharmony_ci const Display = require('../../../lib/utils/display') 971cb0ef41Sopenharmony_ci const customNaN = new CustomObj() 981cb0ef41Sopenharmony_ci const customNull = new CustomObj() 991cb0ef41Sopenharmony_ci const customNumber = new CustomObj() 1001cb0ef41Sopenharmony_ci const customObject = new CustomObj() 1011cb0ef41Sopenharmony_ci const customString = new CustomObj() 1021cb0ef41Sopenharmony_ci const customUndefined = new CustomObj() 1031cb0ef41Sopenharmony_ci customNaN.inspected = NaN 1041cb0ef41Sopenharmony_ci customNull.inspected = null 1051cb0ef41Sopenharmony_ci customNumber.inspected = 477 1061cb0ef41Sopenharmony_ci customObject.inspected = { custom: 'rend\x00ering' } 1071cb0ef41Sopenharmony_ci customString.inspected = 'custom\x00rendering' 1081cb0ef41Sopenharmony_ci customUndefined.inspected = undefined 1091cb0ef41Sopenharmony_ci t.test('strings', async (t) => { 1101cb0ef41Sopenharmony_ci const tests = [ 1111cb0ef41Sopenharmony_ci [477, '477'], 1121cb0ef41Sopenharmony_ci [null, 'null'], 1131cb0ef41Sopenharmony_ci [NaN, 'NaN'], 1141cb0ef41Sopenharmony_ci [true, 'true'], 1151cb0ef41Sopenharmony_ci [undefined, 'undefined'], 1161cb0ef41Sopenharmony_ci ['', ''], 1171cb0ef41Sopenharmony_ci // Cover the bounds of each range and a few characters from inside each range 1181cb0ef41Sopenharmony_ci // \x00 through \x1f 1191cb0ef41Sopenharmony_ci ['hello\x00world', 'hello^@world'], 1201cb0ef41Sopenharmony_ci ['hello\x07world', 'hello^Gworld'], 1211cb0ef41Sopenharmony_ci ['hello\x1bworld', 'hello^[world'], 1221cb0ef41Sopenharmony_ci ['hello\x1eworld', 'hello^^world'], 1231cb0ef41Sopenharmony_ci ['hello\x1fworld', 'hello^_world'], 1241cb0ef41Sopenharmony_ci // \x7f is C0 1251cb0ef41Sopenharmony_ci ['hello\x7fworld', 'hello^?world'], 1261cb0ef41Sopenharmony_ci // \x80 through \x9f 1271cb0ef41Sopenharmony_ci ['hello\x80world', 'hello^@world'], 1281cb0ef41Sopenharmony_ci ['hello\x87world', 'hello^Gworld'], 1291cb0ef41Sopenharmony_ci ['hello\x9eworld', 'hello^^world'], 1301cb0ef41Sopenharmony_ci ['hello\x9fworld', 'hello^_world'], 1311cb0ef41Sopenharmony_ci // Allowed C0 1321cb0ef41Sopenharmony_ci ['hello\tworld', 'hello\tworld'], 1331cb0ef41Sopenharmony_ci ['hello\nworld', 'hello\nworld'], 1341cb0ef41Sopenharmony_ci ['hello\vworld', 'hello\vworld'], 1351cb0ef41Sopenharmony_ci ['hello\rworld', 'hello\rworld'], 1361cb0ef41Sopenharmony_ci // Allowed SGR 1371cb0ef41Sopenharmony_ci ['hello\x1b[38;5;254mworld', 'hello\x1b[38;5;254mworld'], 1381cb0ef41Sopenharmony_ci ['hello\x1b[mworld', 'hello\x1b[mworld'], 1391cb0ef41Sopenharmony_ci // Unallowed CSI / OSC 1401cb0ef41Sopenharmony_ci ['hello\x1b[2Aworld', 'hello^[[2Aworld'], 1411cb0ef41Sopenharmony_ci ['hello\x9b[2Aworld', 'hello^[[2Aworld'], 1421cb0ef41Sopenharmony_ci ['hello\x9decho goodbye\x9cworld', 'hello^]echo goodbye^\\world'], 1431cb0ef41Sopenharmony_ci // This is done twice to ensure we define inspect.custom as writable 1441cb0ef41Sopenharmony_ci [{ test: 'object' }, "{ test: 'object' }"], 1451cb0ef41Sopenharmony_ci [{ test: 'object' }, "{ test: 'object' }"], 1461cb0ef41Sopenharmony_ci // Make sure custom util.inspect doesn't bypass our cleaning 1471cb0ef41Sopenharmony_ci [customNaN, 'NaN'], 1481cb0ef41Sopenharmony_ci [customNull, 'null'], 1491cb0ef41Sopenharmony_ci [customNumber, '477'], 1501cb0ef41Sopenharmony_ci [customObject, "{ custom: 'rend\\x00ering' }"], 1511cb0ef41Sopenharmony_ci [customString, 'custom^@rendering'], 1521cb0ef41Sopenharmony_ci [customUndefined, 'undefined'], 1531cb0ef41Sopenharmony_ci // UTF-16 form of 8-bit C1 1541cb0ef41Sopenharmony_ci ['hello\xc2\x9bworld', 'hello\xc2^[world'], 1551cb0ef41Sopenharmony_ci ] 1561cb0ef41Sopenharmony_ci for (const [dirty, clean] of tests) { 1571cb0ef41Sopenharmony_ci const cleaned = Display.clean(dirty) 1581cb0ef41Sopenharmony_ci t.equal(util.format(cleaned), clean) 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci }) 1611cb0ef41Sopenharmony_ci}) 162