import { suite, test } from 'node:test';
import { deepStrictEqual } from 'node:assert/strict';
-import { csvStreamEqual, csvStreamEqualWritable, createCSVMockStream } from './utils.js';
+import { csvStreamEqual, csvStreamEqualWritable, createCSVMockStream, assertConsole } from './utils.js';
import { CSVReader } from '../src/core.js';
import { toCamelCase, expandScientificNotation, CSVNormalizer, CSVDenormalizer } from '../src/normalization.js';
{ name: 'fixes accounting mangling integer', input: ' $123.00 ', output: 123 },
{ name: 'fixes accounting mangling number', input: ' $123.45 ', output: 123.45 },
{ name: 'fixes accounting mangling with commas', input: ' $10,000,000.00 ', output: 10000000 },
- { name: 'passes through non-number value', input: 'abc', output: 'abc' },
+ { name: 'passes through non-number value', input: 'abc', output: 'abc', consoleCounts: { warn: 1 } },
{ name: 'passes through blank value', input: '', output: '' },
];
- for (const { name, input, output } of vectors) {
- test(name, { concurrency: true }, () => {
+ for (const { name, input, output, consoleCounts } of vectors) {
+ test(name, { concurrency: true }, (t) => {
+ if (consoleCounts !== undefined) {
+ assertConsole(t, consoleCounts);
+ }
deepStrictEqual(CSVNormalizer.fixExcelNumber(input), output);
});
}
{ name: 'fixes accounting mangling integer', input: ' $123.00 ', output: '123' },
{ name: 'fixes accounting mangling number (truncated)', input: ' $123.45 ', output: '123' },
{ name: 'fixes accounting mangling BigInt with commas', input: ' $1,123,123,123,123,123,123.12 ', output: '1123123123123123123' },
- { name: 'passes through non-BigInt values', input: 'abc', output: 'abc' },
+ { name: 'passes through non-BigInt values', input: 'abc', output: 'abc', consoleCounts: { warn: 1 } },
{ name: 'passes through blank value', input: '', output: '' },
];
- for (const { name, input, output } of vectors) {
- test(name, { concurrency: true }, () => {
+ for (const { name, input, output, consoleCounts } of vectors) {
+ test(name, { concurrency: true }, (t) => {
+ if (consoleCounts !== undefined) {
+ assertConsole(t, consoleCounts);
+ }
deepStrictEqual(CSVNormalizer.fixExcelBigInt(input), output);
});
}
{ name: 'fixes number mangling (43915.31372)', input: '43915.31372', output: '2020-03-25T07:31:45.407Z' },
{ name: 'fixes number mangling (44067.63)', input: '44067.63', output: '2020-08-24T15:07:11.999Z' },
{ name: 'fixes number mangling (44309.63502)', input: '44309.63502', output: '2021-04-23T15:14:25.728Z' },
- { name: 'passes through non-date values', input: 'abc', output: 'abc', raw: true },
+ { name: 'passes through non-date values', input: 'abc', output: 'abc', raw: true, consoleCounts: { warn: 1 } },
{ name: 'passes through blank value', input: '', output: '', raw: true },
];
- for (const { name, input, output, raw = false } of vectors) {
- test(name, { concurrency: true }, () => {
+ for (const { name, input, output, raw = false, consoleCounts } of vectors) {
+ test(name, { concurrency: true }, (t) => {
+ if (consoleCounts !== undefined) {
+ assertConsole(t, consoleCounts);
+ }
+
if (raw) {
deepStrictEqual(CSVNormalizer.fixExcelDate(input), output);
}
['a', 'b']
]));
});
- test('can ignore incorrect data types', { concurrency: true }, async () => {
+ test('can ignore incorrect data types', { concurrency: true }, async (t) => {
+ assertConsole(t, { warn: 2 });
await createCSVMockStream([
['columnA', 'columnB'],
['a', 'b']
import { tmpdir } from 'node:os';
import { mkdtemp, open } from 'node:fs/promises';
import { normalize } from 'node:path';
+/** @import { TestContext } from 'node:test'; */
/**
* Log an entire stream along with the field count for each row and the total row count.
});
}
+/**
+ * @typedef AssertConsoleCounts Object containing the total number of times `console.log`, `console.info`, `console.warn`,
+ * and `console.error` are expected to be called.
+ * @property {number} [log=0] The number of times `console.log` is expected to be called.
+ * @property {number} [info=0] The number of times `console.info` is expected to be called.
+ * @property {number} [warn=0] The number of times `console.warn` is expected to be called.
+ * @property {number} [error=0] The number of times `console.error` is expected to be called.
+ */
+
+/**
+ * Silences console functions during a test and asserts a given number of calls were made during the test.
+ *
+ * **Important:** Console will only be silenced AFTER this function is called, and only until the test ends. Call this function
+ * early in the test to avoid unexpected console calls.
+ *
+ * @param {TestContext} context A Node.js `TestContext` for a test case.
+ * @param {AssertConsoleCounts} [expected] Object containing counts for the total number of times console functions are expected
+ * to be called.
+ */
+export function assertConsole(context, expected = {}) {
+ expected.log ??= 0;
+ expected.info ??= 0;
+ expected.warn ??= 0;
+ expected.error ??= 0;
+ const actual = {
+ log: 0,
+ info: 0,
+ warn: 0,
+ error: 0
+ }
+
+ context.mock.method(console, 'log', () => actual.log++);
+ context.mock.method(console, 'info', () => actual.info++);
+ context.mock.method(console, 'warn', () => actual.warn++);
+ context.mock.method(console, 'error', () => actual.error++);
+
+ context.after(() => {
+ deepStrictEqual(actual.log, expected.log, `expected ${expected.log} console.log calls, got ${actual.log}`);
+ deepStrictEqual(actual.info, expected.info, `expected ${expected.info} console.info calls, got ${actual.info}`);
+ deepStrictEqual(actual.warn, expected.warn, `expected ${expected.warn} console.warn calls, got ${actual.warn}`);
+ deepStrictEqual(actual.error, expected.error, `expected ${expected.error} console.error calls, got ${actual.error}`);
+ });
+}
+
/**
* Simulate a stream of CSV data for test mocking purposes.
*