11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst {
31cb0ef41Sopenharmony_ci  ArrayPrototypeJoin,
41cb0ef41Sopenharmony_ci  ArrayPrototypeMap,
51cb0ef41Sopenharmony_ci  ArrayPrototypePush,
61cb0ef41Sopenharmony_ci  ArrayPrototypeReduce,
71cb0ef41Sopenharmony_ci  ObjectCreate,
81cb0ef41Sopenharmony_ci  ObjectGetOwnPropertyDescriptor,
91cb0ef41Sopenharmony_ci  MathFloor,
101cb0ef41Sopenharmony_ci  MathMax,
111cb0ef41Sopenharmony_ci  MathMin,
121cb0ef41Sopenharmony_ci  NumberPrototypeToFixed,
131cb0ef41Sopenharmony_ci  SafePromiseAllReturnArrayLike,
141cb0ef41Sopenharmony_ci  RegExp,
151cb0ef41Sopenharmony_ci  RegExpPrototypeExec,
161cb0ef41Sopenharmony_ci  SafeMap,
171cb0ef41Sopenharmony_ci  StringPrototypePadStart,
181cb0ef41Sopenharmony_ci  StringPrototypePadEnd,
191cb0ef41Sopenharmony_ci  StringPrototypeRepeat,
201cb0ef41Sopenharmony_ci  StringPrototypeSlice,
211cb0ef41Sopenharmony_ci} = primordials;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciconst { AsyncResource } = require('async_hooks');
241cb0ef41Sopenharmony_ciconst { basename, relative } = require('path');
251cb0ef41Sopenharmony_ciconst { createWriteStream } = require('fs');
261cb0ef41Sopenharmony_ciconst { pathToFileURL } = require('internal/url');
271cb0ef41Sopenharmony_ciconst { createDeferredPromise } = require('internal/util');
281cb0ef41Sopenharmony_ciconst { getOptionValue } = require('internal/options');
291cb0ef41Sopenharmony_ciconst { green, yellow, red, white, shouldColorize } = require('internal/util/colors');
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciconst {
321cb0ef41Sopenharmony_ci  codes: {
331cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_VALUE,
341cb0ef41Sopenharmony_ci    ERR_TEST_FAILURE,
351cb0ef41Sopenharmony_ci  },
361cb0ef41Sopenharmony_ci  kIsNodeError,
371cb0ef41Sopenharmony_ci} = require('internal/errors');
381cb0ef41Sopenharmony_ciconst { compose } = require('stream');
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ciconst coverageColors = {
411cb0ef41Sopenharmony_ci  __proto__: null,
421cb0ef41Sopenharmony_ci  high: green,
431cb0ef41Sopenharmony_ci  medium: yellow,
441cb0ef41Sopenharmony_ci  low: red,
451cb0ef41Sopenharmony_ci};
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ciconst kMultipleCallbackInvocations = 'multipleCallbackInvocations';
481cb0ef41Sopenharmony_ciconst kRegExpPattern = /^\/(.*)\/([a-z]*)$/;
491cb0ef41Sopenharmony_ciconst kSupportedFileExtensions = /\.[cm]?js$/;
501cb0ef41Sopenharmony_ciconst kTestFilePattern = /((^test(-.+)?)|(.+[.\-_]test))\.[cm]?js$/;
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_cifunction doesPathMatchFilter(p) {
531cb0ef41Sopenharmony_ci  return RegExpPrototypeExec(kTestFilePattern, basename(p)) !== null;
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_cifunction isSupportedFileType(p) {
571cb0ef41Sopenharmony_ci  return RegExpPrototypeExec(kSupportedFileExtensions, p) !== null;
581cb0ef41Sopenharmony_ci}
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cifunction createDeferredCallback() {
611cb0ef41Sopenharmony_ci  let calledCount = 0;
621cb0ef41Sopenharmony_ci  const { promise, resolve, reject } = createDeferredPromise();
631cb0ef41Sopenharmony_ci  const cb = (err) => {
641cb0ef41Sopenharmony_ci    calledCount++;
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci    // If the callback is called a second time, let the user know, but
671cb0ef41Sopenharmony_ci    // don't let them know more than once.
681cb0ef41Sopenharmony_ci    if (calledCount > 1) {
691cb0ef41Sopenharmony_ci      if (calledCount === 2) {
701cb0ef41Sopenharmony_ci        throw new ERR_TEST_FAILURE(
711cb0ef41Sopenharmony_ci          'callback invoked multiple times',
721cb0ef41Sopenharmony_ci          kMultipleCallbackInvocations,
731cb0ef41Sopenharmony_ci        );
741cb0ef41Sopenharmony_ci      }
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci      return;
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    if (err) {
801cb0ef41Sopenharmony_ci      return reject(err);
811cb0ef41Sopenharmony_ci    }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci    resolve();
841cb0ef41Sopenharmony_ci  };
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  return { __proto__: null, promise, cb };
871cb0ef41Sopenharmony_ci}
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_cifunction isTestFailureError(err) {
901cb0ef41Sopenharmony_ci  return err?.code === 'ERR_TEST_FAILURE' && kIsNodeError in err;
911cb0ef41Sopenharmony_ci}
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_cifunction convertStringToRegExp(str, name) {
941cb0ef41Sopenharmony_ci  const match = RegExpPrototypeExec(kRegExpPattern, str);
951cb0ef41Sopenharmony_ci  const pattern = match?.[1] ?? str;
961cb0ef41Sopenharmony_ci  const flags = match?.[2] || '';
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  try {
991cb0ef41Sopenharmony_ci    return new RegExp(pattern, flags);
1001cb0ef41Sopenharmony_ci  } catch (err) {
1011cb0ef41Sopenharmony_ci    const msg = err?.message;
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_VALUE(
1041cb0ef41Sopenharmony_ci      name,
1051cb0ef41Sopenharmony_ci      str,
1061cb0ef41Sopenharmony_ci      `is an invalid regular expression.${msg ? ` ${msg}` : ''}`,
1071cb0ef41Sopenharmony_ci    );
1081cb0ef41Sopenharmony_ci  }
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ciconst kBuiltinDestinations = new SafeMap([
1121cb0ef41Sopenharmony_ci  ['stdout', process.stdout],
1131cb0ef41Sopenharmony_ci  ['stderr', process.stderr],
1141cb0ef41Sopenharmony_ci]);
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ciconst kBuiltinReporters = new SafeMap([
1171cb0ef41Sopenharmony_ci  ['spec', 'internal/test_runner/reporter/spec'],
1181cb0ef41Sopenharmony_ci  ['dot', 'internal/test_runner/reporter/dot'],
1191cb0ef41Sopenharmony_ci  ['tap', 'internal/test_runner/reporter/tap'],
1201cb0ef41Sopenharmony_ci  ['junit', 'internal/test_runner/reporter/junit'],
1211cb0ef41Sopenharmony_ci]);
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ciconst kDefaultReporter = process.stdout.isTTY ? 'spec' : 'tap';
1241cb0ef41Sopenharmony_ciconst kDefaultDestination = 'stdout';
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_cifunction tryBuiltinReporter(name) {
1271cb0ef41Sopenharmony_ci  const builtinPath = kBuiltinReporters.get(name);
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  if (builtinPath === undefined) {
1301cb0ef41Sopenharmony_ci    return;
1311cb0ef41Sopenharmony_ci  }
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  return require(builtinPath);
1341cb0ef41Sopenharmony_ci}
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ciasync function getReportersMap(reporters, destinations, rootTest) {
1371cb0ef41Sopenharmony_ci  return SafePromiseAllReturnArrayLike(reporters, async (name, i) => {
1381cb0ef41Sopenharmony_ci    const destination = kBuiltinDestinations.get(destinations[i]) ?? createWriteStream(destinations[i]);
1391cb0ef41Sopenharmony_ci    rootTest.harness.shouldColorizeTestFiles ||= shouldColorize(destination);
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    // Load the test reporter passed to --test-reporter
1421cb0ef41Sopenharmony_ci    let reporter = tryBuiltinReporter(name);
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci    if (reporter === undefined) {
1451cb0ef41Sopenharmony_ci      let parentURL;
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci      try {
1481cb0ef41Sopenharmony_ci        parentURL = pathToFileURL(process.cwd() + '/').href;
1491cb0ef41Sopenharmony_ci      } catch {
1501cb0ef41Sopenharmony_ci        parentURL = 'file:///';
1511cb0ef41Sopenharmony_ci      }
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci      const { esmLoader } = require('internal/process/esm_loader');
1541cb0ef41Sopenharmony_ci      reporter = await esmLoader.import(name, parentURL, ObjectCreate(null));
1551cb0ef41Sopenharmony_ci    }
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    if (reporter?.default) {
1581cb0ef41Sopenharmony_ci      reporter = reporter.default;
1591cb0ef41Sopenharmony_ci    }
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci    if (reporter?.prototype && ObjectGetOwnPropertyDescriptor(reporter.prototype, 'constructor')) {
1621cb0ef41Sopenharmony_ci      reporter = new reporter();
1631cb0ef41Sopenharmony_ci    }
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci    if (!reporter) {
1661cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('Reporter', name, 'is not a valid reporter');
1671cb0ef41Sopenharmony_ci    }
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci    return { __proto__: null, reporter, destination };
1701cb0ef41Sopenharmony_ci  });
1711cb0ef41Sopenharmony_ci}
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ciconst reporterScope = new AsyncResource('TestReporterScope');
1741cb0ef41Sopenharmony_ciconst setupTestReporters = reporterScope.bind(async (rootTest) => {
1751cb0ef41Sopenharmony_ci  const { reporters, destinations } = parseCommandLine();
1761cb0ef41Sopenharmony_ci  const reportersMap = await getReportersMap(reporters, destinations, rootTest);
1771cb0ef41Sopenharmony_ci  for (let i = 0; i < reportersMap.length; i++) {
1781cb0ef41Sopenharmony_ci    const { reporter, destination } = reportersMap[i];
1791cb0ef41Sopenharmony_ci    compose(rootTest.reporter, reporter).pipe(destination);
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci});
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_cilet globalTestOptions;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_cifunction parseCommandLine() {
1861cb0ef41Sopenharmony_ci  if (globalTestOptions) {
1871cb0ef41Sopenharmony_ci    return globalTestOptions;
1881cb0ef41Sopenharmony_ci  }
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  const isTestRunner = getOptionValue('--test');
1911cb0ef41Sopenharmony_ci  const coverage = getOptionValue('--experimental-test-coverage');
1921cb0ef41Sopenharmony_ci  const isChildProcess = process.env.NODE_TEST_CONTEXT === 'child';
1931cb0ef41Sopenharmony_ci  const isChildProcessV8 = process.env.NODE_TEST_CONTEXT === 'child-v8';
1941cb0ef41Sopenharmony_ci  let destinations;
1951cb0ef41Sopenharmony_ci  let reporters;
1961cb0ef41Sopenharmony_ci  let testNamePatterns;
1971cb0ef41Sopenharmony_ci  let testOnlyFlag;
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci  if (isChildProcessV8) {
2001cb0ef41Sopenharmony_ci    kBuiltinReporters.set('v8-serializer', 'internal/test_runner/reporter/v8-serializer');
2011cb0ef41Sopenharmony_ci    reporters = ['v8-serializer'];
2021cb0ef41Sopenharmony_ci    destinations = [kDefaultDestination];
2031cb0ef41Sopenharmony_ci  } else if (isChildProcess) {
2041cb0ef41Sopenharmony_ci    reporters = ['tap'];
2051cb0ef41Sopenharmony_ci    destinations = [kDefaultDestination];
2061cb0ef41Sopenharmony_ci  } else {
2071cb0ef41Sopenharmony_ci    destinations = getOptionValue('--test-reporter-destination');
2081cb0ef41Sopenharmony_ci    reporters = getOptionValue('--test-reporter');
2091cb0ef41Sopenharmony_ci    if (reporters.length === 0 && destinations.length === 0) {
2101cb0ef41Sopenharmony_ci      ArrayPrototypePush(reporters, kDefaultReporter);
2111cb0ef41Sopenharmony_ci    }
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci    if (reporters.length === 1 && destinations.length === 0) {
2141cb0ef41Sopenharmony_ci      ArrayPrototypePush(destinations, kDefaultDestination);
2151cb0ef41Sopenharmony_ci    }
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci    if (destinations.length !== reporters.length) {
2181cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE(
2191cb0ef41Sopenharmony_ci        '--test-reporter',
2201cb0ef41Sopenharmony_ci        reporters,
2211cb0ef41Sopenharmony_ci        'must match the number of specified \'--test-reporter-destination\'',
2221cb0ef41Sopenharmony_ci      );
2231cb0ef41Sopenharmony_ci    }
2241cb0ef41Sopenharmony_ci  }
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci  if (isTestRunner) {
2271cb0ef41Sopenharmony_ci    testOnlyFlag = false;
2281cb0ef41Sopenharmony_ci    testNamePatterns = null;
2291cb0ef41Sopenharmony_ci  } else {
2301cb0ef41Sopenharmony_ci    const testNamePatternFlag = getOptionValue('--test-name-pattern');
2311cb0ef41Sopenharmony_ci    testOnlyFlag = getOptionValue('--test-only');
2321cb0ef41Sopenharmony_ci    testNamePatterns = testNamePatternFlag?.length > 0 ?
2331cb0ef41Sopenharmony_ci      ArrayPrototypeMap(
2341cb0ef41Sopenharmony_ci        testNamePatternFlag,
2351cb0ef41Sopenharmony_ci        (re) => convertStringToRegExp(re, '--test-name-pattern'),
2361cb0ef41Sopenharmony_ci      ) : null;
2371cb0ef41Sopenharmony_ci  }
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  globalTestOptions = {
2401cb0ef41Sopenharmony_ci    __proto__: null,
2411cb0ef41Sopenharmony_ci    isTestRunner,
2421cb0ef41Sopenharmony_ci    coverage,
2431cb0ef41Sopenharmony_ci    testOnlyFlag,
2441cb0ef41Sopenharmony_ci    testNamePatterns,
2451cb0ef41Sopenharmony_ci    reporters,
2461cb0ef41Sopenharmony_ci    destinations,
2471cb0ef41Sopenharmony_ci  };
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci  return globalTestOptions;
2501cb0ef41Sopenharmony_ci}
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_cifunction countCompletedTest(test, harness = test.root.harness) {
2531cb0ef41Sopenharmony_ci  if (test.nesting === 0) {
2541cb0ef41Sopenharmony_ci    harness.counters.topLevel++;
2551cb0ef41Sopenharmony_ci  }
2561cb0ef41Sopenharmony_ci  if (test.reportedType === 'suite') {
2571cb0ef41Sopenharmony_ci    harness.counters.suites++;
2581cb0ef41Sopenharmony_ci    return;
2591cb0ef41Sopenharmony_ci  }
2601cb0ef41Sopenharmony_ci  // Check SKIP and TODO tests first, as those should not be counted as
2611cb0ef41Sopenharmony_ci  // failures.
2621cb0ef41Sopenharmony_ci  if (test.skipped) {
2631cb0ef41Sopenharmony_ci    harness.counters.skipped++;
2641cb0ef41Sopenharmony_ci  } else if (test.isTodo) {
2651cb0ef41Sopenharmony_ci    harness.counters.todo++;
2661cb0ef41Sopenharmony_ci  } else if (test.cancelled) {
2671cb0ef41Sopenharmony_ci    harness.counters.cancelled++;
2681cb0ef41Sopenharmony_ci  } else if (!test.passed) {
2691cb0ef41Sopenharmony_ci    harness.counters.failed++;
2701cb0ef41Sopenharmony_ci  } else {
2711cb0ef41Sopenharmony_ci    harness.counters.passed++;
2721cb0ef41Sopenharmony_ci  }
2731cb0ef41Sopenharmony_ci  harness.counters.all++;
2741cb0ef41Sopenharmony_ci}
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ciconst memo = new SafeMap();
2781cb0ef41Sopenharmony_cifunction addTableLine(prefix, width) {
2791cb0ef41Sopenharmony_ci  const key = `${prefix}-${width}`;
2801cb0ef41Sopenharmony_ci  let value = memo.get(key);
2811cb0ef41Sopenharmony_ci  if (value === undefined) {
2821cb0ef41Sopenharmony_ci    value = `${prefix}${StringPrototypeRepeat('-', width)}\n`;
2831cb0ef41Sopenharmony_ci    memo.set(key, value);
2841cb0ef41Sopenharmony_ci  }
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci  return value;
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ciconst kHorizontalEllipsis = '\u2026';
2901cb0ef41Sopenharmony_cifunction truncateStart(string, width) {
2911cb0ef41Sopenharmony_ci  return string.length > width ? `${kHorizontalEllipsis}${StringPrototypeSlice(string, string.length - width + 1)}` : string;
2921cb0ef41Sopenharmony_ci}
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_cifunction truncateEnd(string, width) {
2951cb0ef41Sopenharmony_ci  return string.length > width ? `${StringPrototypeSlice(string, 0, width - 1)}${kHorizontalEllipsis}` : string;
2961cb0ef41Sopenharmony_ci}
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_cifunction formatLinesToRanges(values) {
2991cb0ef41Sopenharmony_ci  return ArrayPrototypeMap(ArrayPrototypeReduce(values, (prev, current, index, array) => {
3001cb0ef41Sopenharmony_ci    if ((index > 0) && ((current - array[index - 1]) === 1)) {
3011cb0ef41Sopenharmony_ci      prev[prev.length - 1][1] = current;
3021cb0ef41Sopenharmony_ci    } else {
3031cb0ef41Sopenharmony_ci      prev.push([current]);
3041cb0ef41Sopenharmony_ci    }
3051cb0ef41Sopenharmony_ci    return prev;
3061cb0ef41Sopenharmony_ci  }, []), (range) => ArrayPrototypeJoin(range, '-'));
3071cb0ef41Sopenharmony_ci}
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_cifunction formatUncoveredLines(lines, table) {
3101cb0ef41Sopenharmony_ci  if (table) return ArrayPrototypeJoin(formatLinesToRanges(lines), ' ');
3111cb0ef41Sopenharmony_ci  return ArrayPrototypeJoin(lines, ', ');
3121cb0ef41Sopenharmony_ci}
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ciconst kColumns = ['line %', 'branch %', 'funcs %'];
3151cb0ef41Sopenharmony_ciconst kColumnsKeys = ['coveredLinePercent', 'coveredBranchPercent', 'coveredFunctionPercent'];
3161cb0ef41Sopenharmony_ciconst kSeparator = ' | ';
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_cifunction getCoverageReport(pad, summary, symbol, color, table) {
3191cb0ef41Sopenharmony_ci  const prefix = `${pad}${symbol}`;
3201cb0ef41Sopenharmony_ci  let report = `${color}${prefix}start of coverage report\n`;
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci  let filePadLength;
3231cb0ef41Sopenharmony_ci  let columnPadLengths = [];
3241cb0ef41Sopenharmony_ci  let uncoveredLinesPadLength;
3251cb0ef41Sopenharmony_ci  let tableWidth;
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci  if (table) {
3281cb0ef41Sopenharmony_ci    // Get expected column sizes
3291cb0ef41Sopenharmony_ci    filePadLength = table && ArrayPrototypeReduce(summary.files, (acc, file) =>
3301cb0ef41Sopenharmony_ci      MathMax(acc, relative(summary.workingDirectory, file.path).length), 0);
3311cb0ef41Sopenharmony_ci    filePadLength = MathMax(filePadLength, 'file'.length);
3321cb0ef41Sopenharmony_ci    const fileWidth = filePadLength + 2;
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci    columnPadLengths = ArrayPrototypeMap(kColumns, (column) => (table ? MathMax(column.length, 6) : 0));
3351cb0ef41Sopenharmony_ci    const columnsWidth = ArrayPrototypeReduce(columnPadLengths, (acc, columnPadLength) => acc + columnPadLength + 3, 0);
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci    uncoveredLinesPadLength = table && ArrayPrototypeReduce(summary.files, (acc, file) =>
3381cb0ef41Sopenharmony_ci      MathMax(acc, formatUncoveredLines(file.uncoveredLineNumbers, table).length), 0);
3391cb0ef41Sopenharmony_ci    uncoveredLinesPadLength = MathMax(uncoveredLinesPadLength, 'uncovered lines'.length);
3401cb0ef41Sopenharmony_ci    const uncoveredLinesWidth = uncoveredLinesPadLength + 2;
3411cb0ef41Sopenharmony_ci
3421cb0ef41Sopenharmony_ci    tableWidth = fileWidth + columnsWidth + uncoveredLinesWidth;
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci    // Fit with sensible defaults
3451cb0ef41Sopenharmony_ci    const availableWidth = (process.stdout.columns || Infinity) - prefix.length;
3461cb0ef41Sopenharmony_ci    const columnsExtras = tableWidth - availableWidth;
3471cb0ef41Sopenharmony_ci    if (table && columnsExtras > 0) {
3481cb0ef41Sopenharmony_ci      // Ensure file name is sufficiently visible
3491cb0ef41Sopenharmony_ci      const minFilePad = MathMin(8, filePadLength);
3501cb0ef41Sopenharmony_ci      filePadLength -= MathFloor(columnsExtras * 0.2);
3511cb0ef41Sopenharmony_ci      filePadLength = MathMax(filePadLength, minFilePad);
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci      // Get rest of available space, subtracting margins
3541cb0ef41Sopenharmony_ci      uncoveredLinesPadLength = MathMax(availableWidth - columnsWidth - (filePadLength + 2) - 2, 1);
3551cb0ef41Sopenharmony_ci
3561cb0ef41Sopenharmony_ci      // Update table width
3571cb0ef41Sopenharmony_ci      tableWidth = availableWidth;
3581cb0ef41Sopenharmony_ci    } else {
3591cb0ef41Sopenharmony_ci      uncoveredLinesPadLength = Infinity;
3601cb0ef41Sopenharmony_ci    }
3611cb0ef41Sopenharmony_ci  }
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  function getCell(string, width, pad, truncate, coverage) {
3651cb0ef41Sopenharmony_ci    if (!table) return string;
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_ci    let result = string;
3681cb0ef41Sopenharmony_ci    if (pad) result = pad(result, width);
3691cb0ef41Sopenharmony_ci    if (truncate) result = truncate(result, width);
3701cb0ef41Sopenharmony_ci    if (color && coverage !== undefined) {
3711cb0ef41Sopenharmony_ci      if (coverage > 90) return `${coverageColors.high}${result}${color}`;
3721cb0ef41Sopenharmony_ci      if (coverage > 50) return `${coverageColors.medium}${result}${color}`;
3731cb0ef41Sopenharmony_ci      return `${coverageColors.low}${result}${color}`;
3741cb0ef41Sopenharmony_ci    }
3751cb0ef41Sopenharmony_ci    return result;
3761cb0ef41Sopenharmony_ci  }
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci  // Head
3791cb0ef41Sopenharmony_ci  if (table) report += addTableLine(prefix, tableWidth);
3801cb0ef41Sopenharmony_ci  report += `${prefix}${getCell('file', filePadLength, StringPrototypePadEnd, truncateEnd)}${kSeparator}` +
3811cb0ef41Sopenharmony_ci            `${ArrayPrototypeJoin(ArrayPrototypeMap(kColumns, (column, i) => getCell(column, columnPadLengths[i], StringPrototypePadStart)), kSeparator)}${kSeparator}` +
3821cb0ef41Sopenharmony_ci            `${getCell('uncovered lines', uncoveredLinesPadLength, false, truncateEnd)}\n`;
3831cb0ef41Sopenharmony_ci  if (table) report += addTableLine(prefix, tableWidth);
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci  // Body
3861cb0ef41Sopenharmony_ci  for (let i = 0; i < summary.files.length; ++i) {
3871cb0ef41Sopenharmony_ci    const file = summary.files[i];
3881cb0ef41Sopenharmony_ci    const relativePath = relative(summary.workingDirectory, file.path);
3891cb0ef41Sopenharmony_ci
3901cb0ef41Sopenharmony_ci    let fileCoverage = 0;
3911cb0ef41Sopenharmony_ci    const coverages = ArrayPrototypeMap(kColumnsKeys, (columnKey) => {
3921cb0ef41Sopenharmony_ci      const percent = file[columnKey];
3931cb0ef41Sopenharmony_ci      fileCoverage += percent;
3941cb0ef41Sopenharmony_ci      return percent;
3951cb0ef41Sopenharmony_ci    });
3961cb0ef41Sopenharmony_ci    fileCoverage /= kColumnsKeys.length;
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci    report += `${prefix}${getCell(relativePath, filePadLength, StringPrototypePadEnd, truncateStart, fileCoverage)}${kSeparator}` +
3991cb0ef41Sopenharmony_ci              `${ArrayPrototypeJoin(ArrayPrototypeMap(coverages, (coverage, j) => getCell(NumberPrototypeToFixed(coverage, 2), columnPadLengths[j], StringPrototypePadStart, false, coverage)), kSeparator)}${kSeparator}` +
4001cb0ef41Sopenharmony_ci              `${getCell(formatUncoveredLines(file.uncoveredLineNumbers, table), uncoveredLinesPadLength, false, truncateEnd)}\n`;
4011cb0ef41Sopenharmony_ci  }
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  // Foot
4041cb0ef41Sopenharmony_ci  if (table) report += addTableLine(prefix, tableWidth);
4051cb0ef41Sopenharmony_ci  report += `${prefix}${getCell('all files', filePadLength, StringPrototypePadEnd, truncateEnd)}${kSeparator}` +
4061cb0ef41Sopenharmony_ci            `${ArrayPrototypeJoin(ArrayPrototypeMap(kColumnsKeys, (columnKey, j) => getCell(NumberPrototypeToFixed(summary.totals[columnKey], 2), columnPadLengths[j], StringPrototypePadStart, false, summary.totals[columnKey])), kSeparator)} |\n`;
4071cb0ef41Sopenharmony_ci  if (table) report += addTableLine(prefix, tableWidth);
4081cb0ef41Sopenharmony_ci
4091cb0ef41Sopenharmony_ci  report += `${prefix}end of coverage report\n`;
4101cb0ef41Sopenharmony_ci  if (color) {
4111cb0ef41Sopenharmony_ci    report += white;
4121cb0ef41Sopenharmony_ci  }
4131cb0ef41Sopenharmony_ci  return report;
4141cb0ef41Sopenharmony_ci}
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_cimodule.exports = {
4171cb0ef41Sopenharmony_ci  convertStringToRegExp,
4181cb0ef41Sopenharmony_ci  countCompletedTest,
4191cb0ef41Sopenharmony_ci  createDeferredCallback,
4201cb0ef41Sopenharmony_ci  doesPathMatchFilter,
4211cb0ef41Sopenharmony_ci  isSupportedFileType,
4221cb0ef41Sopenharmony_ci  isTestFailureError,
4231cb0ef41Sopenharmony_ci  parseCommandLine,
4241cb0ef41Sopenharmony_ci  reporterScope,
4251cb0ef41Sopenharmony_ci  setupTestReporters,
4261cb0ef41Sopenharmony_ci  getCoverageReport,
4271cb0ef41Sopenharmony_ci};
428