Skip to main content
Module

std/csv/stringify_test.ts

Deno standard library
Go to Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
// Test ported from Golang// https://github.com/golang/go/blob/2cc15b1/src/encoding/csv/reader_test.go// Copyright 2011 The Go Authors. All rights reserved. BSD license.// https://github.com/golang/go/blob/master/LICENSE// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { assert, assertEquals, assertStringIncludes, assertThrows,} from "../testing/asserts.ts";import { stringify, StringifyError } from "./stringify.ts";
const CRLF = "\r\n";const BYTE_ORDER_MARK = "\ufeff";
Deno.test({ name: "stringify", async fn(t) { await t.step({ name: "Access array index using string", fn() { const columns = ["a"]; const data = [["foo"], ["bar"]]; const errorMessage = 'Property accessor is not of type "number"'; assertThrows( () => stringify(data, { columns }), StringifyError, errorMessage, ); }, }); await t.step( { name: "Double quote in separator",
fn() { const columns = [0]; const data = [["foo"], ["bar"]]; const errorMessage = [ "Separator cannot include the following strings:", ' - U+0022: Quotation mark (")', " - U+000D U+000A: Carriage Return + Line Feed (\\r\\n)", ].join("\n"); const options = { separator: '"', columns }; assertThrows( () => stringify(data, options), StringifyError, errorMessage, ); }, }, ); await t.step( { name: "CRLF in separator", fn() { const columns = [0]; const data = [["foo"], ["bar"]]; const errorMessage = [ "Separator cannot include the following strings:", ' - U+0022: Quotation mark (")', " - U+000D U+000A: Carriage Return + Line Feed (\\r\\n)", ].join("\n"); const options = { separator: "\r\n", columns }; assertThrows( () => stringify(data, options), StringifyError, errorMessage, ); }, }, );
await t.step( { name: "Invalid data, no columns", fn() { const data = [{ a: 1 }, { a: 2 }]; assertThrows( () => stringify(data), StringifyError, "No property accessor function was provided for object", ); }, }, ); await t.step( { name: "Invalid data, no columns", fn() { const data = [{ a: 1 }, { a: 2 }]; assertThrows( () => stringify(data), StringifyError, "No property accessor function was provided for object", ); }, }, ); await t.step( { name: "No data, no columns",
fn() { const columns: string[] = []; const data: string[][] = []; const output = CRLF; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "No data, no columns, no headers", fn() { const columns: string[] = []; const data: string[][] = []; const output = ``; const options = { headers: false, columns }; assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "No data, columns", fn() { const columns = ["a"]; const data: string[][] = []; const output = `a${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "No data, columns, no headers",
fn() { const columns = ["a"]; const data: string[][] = []; const output = ``; const options = { headers: false, columns }; assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "Separator: CR", fn() { const columns = [0, 1]; const data = [["foo", "bar"], ["baz", "qux"]]; const output = `0\r1${CRLF}foo\rbar${CRLF}baz\rqux${CRLF}`; const options = { separator: "\r", columns }; assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "Separator: LF",
fn() { const columns = [0, 1]; const data = [["foo", "bar"], ["baz", "qux"]]; const output = `0\n1${CRLF}foo\nbar${CRLF}baz\nqux${CRLF}`; const options = { separator: "\n", columns }; assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "Column: number accessor", fn() { const columns = [1]; const data = [{ 1: 1 }, { 1: 2 }]; const output = `1${CRLF}1${CRLF}2${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Explicit header value, no headers",
fn() { const columns = [{ header: "Value", prop: "value" }]; const data = [{ value: "foo" }, { value: "bar" }]; const output = `foo${CRLF}bar${CRLF}`; const options = { headers: false, columns }; assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "Column: number accessor,const data = array", fn() { const columns = [1]; const data = [["key", "foo"], ["key", "bar"]]; const output = `1${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Column: array number accessor",
fn() { const columns = [[1]]; const data = [{ 1: 1 }, { 1: 2 }]; const output = `1${CRLF}1${CRLF}2${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Column: array number accessor,const data = array", fn() { const columns = [[1]]; const data = [["key", "foo"], ["key", "bar"]]; const output = `1${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Column: array number accessor,const data = array",
fn() { const columns = [[1, 1]]; const data = [["key", ["key", "foo"]], ["key", ["key", "bar"]]]; const output = `1${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Column: string accessor", fn() { const columns = ["value"]; const data = [{ value: "foo" }, { value: "bar" }]; const output = `value${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Column: array string accessor", fn() { const columns = [["value"]]; const data = [{ value: "foo" }, { value: "bar" }]; const output = `value${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Column: array string accessor", fn() { const columns = [["msg", "value"]]; const data = [{ msg: { value: "foo" } }, { msg: { value: "bar" } }]; const output = `value${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Explicit header", fn() { const columns = [ { header: "Value", prop: ["msg", "value"], }, ]; const data = [{ msg: { value: "foo" } }, { msg: { value: "bar" } }]; const output = `Value${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, );
await t.step( { name: "Targeted value: object", fn() { const columns = [0]; const data = [[{ value: "foo" }], [{ value: "bar" }]]; const output = `0${CRLF}"{""value"":""foo""}"${CRLF}"{""value"":""bar""}"${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: arary of objects", fn() { const columns = [0]; const data = [ [[{ value: "foo" }, { value: "bar" }]], [[{ value: "baz" }, { value: "qux" }]], ]; const output = `0${CRLF}"[{""value"":""foo""},{""value"":""bar""}]"${CRLF}"[{""value"":""baz""},{""value"":""qux""}]"${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: array", fn() { const columns = [0]; const data = [[["foo", "bar"]], [["baz", "qux"]]]; const output = `0${CRLF}"[""foo"",""bar""]"${CRLF}"[""baz"",""qux""]"${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: array, separator: tab",
fn() { const columns = [0]; const data = [[["foo", "bar"]], [["baz", "qux"]]]; const output = `0${CRLF}"[""foo"",""bar""]"${CRLF}"[""baz"",""qux""]"${CRLF}`; const options = { separator: "\t", columns }; assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "Targeted value: undefined", fn() { const columns = [0]; const data = [[], []]; const output = `0${CRLF}${CRLF}${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: null", fn() { const columns = [0]; const data = [[null], [null]]; const output = `0${CRLF}${CRLF}${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: hex number", fn() { const columns = [0]; const data = [[0xa], [0xb]]; const output = `0${CRLF}10${CRLF}11${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: BigInt", fn() { const columns = [0]; const data = [[BigInt("1")], [BigInt("2")]]; const output = `0${CRLF}1${CRLF}2${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: boolean", fn() { const columns = [0]; const data = [[true], [false]]; const output = `0${CRLF}true${CRLF}false${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: string", fn() { const columns = [0]; const data = [["foo"], ["bar"]]; const output = `0${CRLF}foo${CRLF}bar${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: symbol", fn() { const columns = [0]; const data = [[Symbol("foo")], [Symbol("bar")]]; const output = `0${CRLF}Symbol(foo)${CRLF}Symbol(bar)${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Targeted value: function", fn() { const columns = [0]; const data = [[(n: number) => n]]; const output = `0${CRLF}(n)=>n${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Value with double quote", fn() { const columns = [0]; const data = [['foo"']]; const output = `0${CRLF}"foo"""${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Value with CRLF", fn() { const columns = [0]; const data = [["foo\r\n"]]; const output = `0${CRLF}"foo\r\n"${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Value with CR", fn() { const columns = [0]; const data = [["foo\r"]]; const output = `0${CRLF}foo\r${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Value with LF", fn() { const columns = [0]; const data = [["foo\n"]]; const output = `0${CRLF}"foo\n"${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Value with comma", fn() { const columns = [0]; const data = [["foo,"]]; const output = `0${CRLF}"foo,"${CRLF}`; assertEquals(stringify(data, { columns }), output); }, }, ); await t.step( { name: "Value with comma, tab separator", fn() { const columns = [0]; const data = [["foo,"]]; const output = `0${CRLF}foo,${CRLF}`;
const options = { separator: "\t", columns }; assertEquals(stringify(data, options), output); }, }, ); await t.step({ name: "Valid data, no columns", fn() { const data = [[1, 2, 3], [4, 5, 6]]; const output = `${CRLF}1,2,3${CRLF}4,5,6${CRLF}`;
assertEquals(stringify(data), output); }, }); await t.step( { name: "byte-order mark with bom=true", fn() { const data = [["abc"]]; const output = `${BYTE_ORDER_MARK}abc${CRLF}`; const options = { headers: false, bom: true }; assertStringIncludes(stringify(data, options), BYTE_ORDER_MARK); assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "no byte-order mark with omitted bom option", fn() { const data = [["abc"]]; const output = `abc${CRLF}`; const options = { headers: false }; assert(!stringify(data, options).includes(BYTE_ORDER_MARK)); assertEquals(stringify(data, options), output); }, }, ); await t.step( { name: "no byte-order mark with bom=false", fn() { const data = [["abc"]]; const output = `abc${CRLF}`; const options = { headers: false, bom: false }; assert(!stringify(data, options).includes(BYTE_ORDER_MARK)); assertEquals(stringify(data, options), output); }, }, ); },});