std/encoding/csv_stringify_test.ts
2022-02-02 23:21:39 +09:00

374 lines
10 KiB
TypeScript

// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { assertEquals, assertRejects } from "../testing/asserts.ts";
import {
Column,
DataItem,
NEWLINE,
stringify,
StringifyError,
StringifyOptions,
} from "./csv_stringify.ts";
type StringifyTestCaseBase = {
columns: Column[];
data: DataItem[];
name: string;
options?: StringifyOptions;
};
type StringifyTestCaseError = StringifyTestCaseBase & {
errorMessage?: string;
// deno-lint-ignore no-explicit-any
throwsError: new (...args: any[]) => Error;
};
type StringifyTestCase = StringifyTestCaseBase & { expected: string };
const stringifyTestCases: (StringifyTestCase | StringifyTestCaseError)[] = [
{
columns: ["a"],
data: [["foo"], ["bar"]],
errorMessage: 'Property accessor is not of type "number"',
name: "[CSV_stringify] Access array index using string",
throwsError: StringifyError,
},
{
columns: [0],
data: [["foo"], ["bar"]],
errorMessage: [
"Separator cannot include the following strings:",
' - U+0022: Quotation mark (")',
" - U+000D U+000A: Carriage Return + Line Feed (\\r\\n)",
].join("\n"),
name: "[CSV_stringify] Double quote in separator",
options: { separator: '"' },
throwsError: StringifyError,
},
{
columns: [0],
data: [["foo"], ["bar"]],
errorMessage: [
"Separator cannot include the following strings:",
' - U+0022: Quotation mark (")',
" - U+000D U+000A: Carriage Return + Line Feed (\\r\\n)",
].join("\n"),
name: "[CSV_stringify] CRLF in separator",
options: { separator: "\r\n" },
throwsError: StringifyError,
},
{
columns: [
{
fn: (obj) => obj.toUpperCase(),
prop: "msg",
},
],
data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }],
name: "[CSV_stringify] Transform function",
throwsError: TypeError,
},
{
columns: [],
data: [],
expected: NEWLINE,
name: "[CSV_stringify] No data, no columns",
},
{
columns: [],
data: [],
expected: ``,
name: "[CSV_stringify] No data, no columns, no headers",
options: { headers: false },
},
{
columns: ["a"],
data: [],
expected: `a${NEWLINE}`,
name: "[CSV_stringify] No data, columns",
},
{
columns: ["a"],
data: [],
expected: ``,
name: "[CSV_stringify] No data, columns, no headers",
options: { headers: false },
},
{
columns: [],
data: [{ a: 1 }, { a: 2 }],
expected: `${NEWLINE}${NEWLINE}${NEWLINE}`,
name: "[CSV_stringify] Data, no columns",
},
{
columns: [0, 1],
data: [["foo", "bar"], ["baz", "qux"]],
expected: `0\r1${NEWLINE}foo\rbar${NEWLINE}baz\rqux${NEWLINE}`,
name: "[CSV_stringify] Separator: CR",
options: { separator: "\r" },
},
{
columns: [0, 1],
data: [["foo", "bar"], ["baz", "qux"]],
expected: `0\n1${NEWLINE}foo\nbar${NEWLINE}baz\nqux${NEWLINE}`,
name: "[CSV_stringify] Separator: LF",
options: { separator: "\n" },
},
{
columns: [1],
data: [{ 1: 1 }, { 1: 2 }],
expected: `1${NEWLINE}1${NEWLINE}2${NEWLINE}`,
name: "[CSV_stringify] Column: number accessor, Data: object",
},
{
columns: [{ header: "Value", prop: "value" }],
data: [{ value: "foo" }, { value: "bar" }],
expected: `foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Explicit header value, no headers",
options: { headers: false },
},
{
columns: [1],
data: [["key", "foo"], ["key", "bar"]],
expected: `1${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Column: number accessor, Data: array",
},
{
columns: [[1]],
data: [{ 1: 1 }, { 1: 2 }],
expected: `1${NEWLINE}1${NEWLINE}2${NEWLINE}`,
name: "[CSV_stringify] Column: array number accessor, Data: object",
},
{
columns: [[1]],
data: [["key", "foo"], ["key", "bar"]],
expected: `1${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Column: array number accessor, Data: array",
},
{
columns: [[1, 1]],
data: [["key", ["key", "foo"]], ["key", ["key", "bar"]]],
expected: `1${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Column: array number accessor, Data: array",
},
{
columns: ["value"],
data: [{ value: "foo" }, { value: "bar" }],
expected: `value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Column: string accessor, Data: object",
},
{
columns: [["value"]],
data: [{ value: "foo" }, { value: "bar" }],
expected: `value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Column: array string accessor, Data: object",
},
{
columns: [["msg", "value"]],
data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }],
expected: `value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Column: array string accessor, Data: object",
},
{
columns: [
{
header: "Value",
prop: ["msg", "value"],
},
],
data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }],
expected: `Value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Explicit header",
},
{
columns: [
{
fn: (str: string) => str.toUpperCase(),
prop: ["msg", "value"],
},
],
data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }],
expected: `value${NEWLINE}FOO${NEWLINE}BAR${NEWLINE}`,
name: "[CSV_stringify] Transform function 1",
},
{
columns: [
{
fn: (str: string) => Promise.resolve(str.toUpperCase()),
prop: ["msg", "value"],
},
],
data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }],
expected: `value${NEWLINE}FOO${NEWLINE}BAR${NEWLINE}`,
name: "[CSV_stringify] Transform function 1 async",
},
{
columns: [
{
fn: (obj: { value: string }) => obj.value,
prop: "msg",
},
],
data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }],
expected: `msg${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Transform function 2",
},
{
columns: [
{
fn: (obj: { value: string }) => obj.value,
header: "Value",
prop: "msg",
},
],
data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }],
expected: `Value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Transform function 2, explicit header",
},
{
columns: [0],
data: [[{ value: "foo" }], [{ value: "bar" }]],
expected:
`0${NEWLINE}"{""value"":""foo""}"${NEWLINE}"{""value"":""bar""}"${NEWLINE}`,
name: "[CSV_stringify] Targeted value: object",
},
{
columns: [0],
data: [
[[{ value: "foo" }, { value: "bar" }]],
[[{ value: "baz" }, { value: "qux" }]],
],
expected:
`0${NEWLINE}"[{""value"":""foo""},{""value"":""bar""}]"${NEWLINE}"[{""value"":""baz""},{""value"":""qux""}]"${NEWLINE}`,
name: "[CSV_stringify] Targeted value: arary of objects",
},
{
columns: [0],
data: [[["foo", "bar"]], [["baz", "qux"]]],
expected:
`0${NEWLINE}"[""foo"",""bar""]"${NEWLINE}"[""baz"",""qux""]"${NEWLINE}`,
name: "[CSV_stringify] Targeted value: array",
},
{
columns: [0],
data: [[["foo", "bar"]], [["baz", "qux"]]],
expected:
`0${NEWLINE}"[""foo"",""bar""]"${NEWLINE}"[""baz"",""qux""]"${NEWLINE}`,
name: "[CSV_stringify] Targeted value: array, separator: tab",
options: { separator: "\t" },
},
{
columns: [0],
data: [[], []],
expected: `0${NEWLINE}${NEWLINE}${NEWLINE}`,
name: "[CSV_stringify] Targeted value: undefined",
},
{
columns: [0],
data: [[null], [null]],
expected: `0${NEWLINE}${NEWLINE}${NEWLINE}`,
name: "[CSV_stringify] Targeted value: null",
},
{
columns: [0],
data: [[0xa], [0xb]],
expected: `0${NEWLINE}10${NEWLINE}11${NEWLINE}`,
name: "[CSV_stringify] Targeted value: hex number",
},
{
columns: [0],
data: [[BigInt("1")], [BigInt("2")]],
expected: `0${NEWLINE}1${NEWLINE}2${NEWLINE}`,
name: "[CSV_stringify] Targeted value: BigInt",
},
{
columns: [0],
data: [[true], [false]],
expected: `0${NEWLINE}true${NEWLINE}false${NEWLINE}`,
name: "[CSV_stringify] Targeted value: boolean",
},
{
columns: [0],
data: [["foo"], ["bar"]],
expected: `0${NEWLINE}foo${NEWLINE}bar${NEWLINE}`,
name: "[CSV_stringify] Targeted value: string",
},
{
columns: [0],
data: [[Symbol("foo")], [Symbol("bar")]],
expected: `0${NEWLINE}Symbol(foo)${NEWLINE}Symbol(bar)${NEWLINE}`,
name: "[CSV_stringify] Targeted value: symbol",
},
{
columns: [0],
data: [[(n: number) => n]],
expected: `0${NEWLINE}(n) => n${NEWLINE}`,
name: "[CSV_stringify] Targeted value: function",
},
{
columns: [0],
data: [['foo"']],
expected: `0${NEWLINE}"foo"""${NEWLINE}`,
name: "[CSV_stringify] Value with double quote",
},
{
columns: [0],
data: [["foo\r\n"]],
expected: `0${NEWLINE}"foo\r\n"${NEWLINE}`,
name: "[CSV_stringify] Value with CRLF",
},
{
columns: [0],
data: [["foo\r"]],
expected: `0${NEWLINE}foo\r${NEWLINE}`,
name: "[CSV_stringify] Value with CR",
},
{
columns: [0],
data: [["foo\n"]],
expected: `0${NEWLINE}foo\n${NEWLINE}`,
name: "[CSV_stringify] Value with LF",
},
{
columns: [0],
data: [["foo,"]],
expected: `0${NEWLINE}"foo,"${NEWLINE}`,
name: "[CSV_stringify] Value with comma",
},
{
columns: [0],
data: [["foo,"]],
expected: `0${NEWLINE}foo,${NEWLINE}`,
name: "[CSV_stringify] Value with comma, tab separator",
options: { separator: "\t" },
},
];
for (const tc of stringifyTestCases) {
if ((tc as StringifyTestCaseError).throwsError) {
const t = tc as StringifyTestCaseError;
Deno.test({
async fn() {
await assertRejects(
async () => {
await stringify(t.data, t.columns, t.options);
},
t.throwsError,
t.errorMessage,
);
},
name: t.name,
});
} else {
const t = tc as StringifyTestCase;
Deno.test({
async fn() {
const actual = await stringify(t.data, t.columns, t.options);
assertEquals(actual, t.expected);
},
name: t.name,
});
}
}