From: Ardis Lu Date: Wed, 8 Jan 2025 06:24:25 +0000 (-0800) Subject: Push one empty row if CSV is blank X-Git-Tag: v0.1.0~139 X-Git-Url: https://git.ardis.lu/?a=commitdiff_plain;h=4f7beacd469494cf22ed94d603e19819e9bd7108;p=csvio Push one empty row if CSV is blank Added a negative test to catch this edge case because it was not caught with the positive test case. --- diff --git a/src/core.js b/src/core.js index 2091987..18920cb 100644 --- a/src/core.js +++ b/src/core.js @@ -95,6 +95,9 @@ export function createCSVReadableStream(path) { row.push(field); // Last field is always un-pushed if CSV terminated with nothing controller.enqueue(JSON.stringify(row)); } + else if (lastChar === null) { // CSV is blank + controller.enqueue(JSON.stringify([''])); + } } })); } diff --git a/test/core.test.js b/test/core.test.js index fe960b3..e52b6bc 100644 --- a/test/core.test.js +++ b/test/core.test.js @@ -2,7 +2,7 @@ import { suite, test } from 'node:test'; import { deepStrictEqual } from 'node:assert/strict'; import { unlink } from 'node:fs/promises'; -import { csvStreamEqualWritable, createCSVMockStream, createTempFile } from './utils.js'; +import { csvStreamEqualWritable, csvStreamNotEqualWritable, createCSVMockStream, createTempFile } from './utils.js'; import { arrayToCSVString, createCSVReadableStream, createCSVTransformStream, createCSVWritableStream } from '../src/core.js'; suite('arrayToCSVString', { concurrency: true }, () => { @@ -146,12 +146,18 @@ suite('createCSVReadableStream', { concurrency: true }, () => { input: './test/data/blank.csv', output: [ [''] + ], + negativeOutput: [ + ['a'] ] } ]; - for (const { name, input, output } of vectors) { + for (const { name, input, output, negativeOutput } of vectors) { test(name, { concurrency: true }, async () => { await createCSVReadableStream(input).pipeTo(csvStreamEqualWritable(output)); + if (negativeOutput !== undefined) { + await createCSVReadableStream(input).pipeTo(csvStreamNotEqualWritable(negativeOutput)); + } }); } }); diff --git a/test/utils.js b/test/utils.js index d95aa4c..8d725c9 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,4 +1,4 @@ -import { deepStrictEqual } from 'node:assert/strict'; +import { deepStrictEqual, notStrictEqual } from 'node:assert/strict'; import { tmpdir } from 'node:os'; import { open } from 'node:fs/promises'; import { normalize } from 'node:path'; @@ -66,6 +66,43 @@ export function csvStreamEqualWritable(csv) { }); } +/** + * Negative version of `csvStreamEqual`. Tests that the given stream is NOT equal to the given CSV. + * + * @param {ReadableStream} stream A stream of CSV data. + * @param {Array>} csv A 2-D array representing the CSV file, where each inner array + */ +export async function csvStreamNotEqual(stream, csv) { + let i = 0; + for await (const value of stream) { + const row = JSON.parse(value); + for (let j = 0; j < csv[i].length; j++) { + notStrictEqual(row[j], csv[i][j]); + } + i++; + } +} + +/** + * Negative version of `csvStreamEqualWritable`. Tests that the piped stream is NOT equal to the given CSV. + * + * @param {Array>} csv A 2-D array representing the CSV file, where each inner array + * is a row of the CSV. + * @returns {WritableStream} A `WritableStream` sink of a CSV stream that will be compared against the given array. + */ +export function csvStreamNotEqualWritable(csv) { + let i = 0; + return new WritableStream({ + write(chunk) { + const row = JSON.parse(chunk); + for (let j = 0; j < csv[i].length; j++) { + notStrictEqual(row[j], csv[i][j]); + } + i++; + } + }); +} + /** * Simulate a stream of CSV data for test mocking purposes. *