blob: cd124a537d12615bb887d269b2d387d9bf15981d [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {assert} from 'chai';
6import sinon from 'sinon';
7import {
8 constructHref,
9 convertListContentToCsv,
10 prepareDataForDownload,
11 preventCSVInjectionAndStringify,
12} from './list-to-csv-helpers.js';
13
14describe('constructHref', () => {
15 it('has default of empty string', () => {
16 const result = constructHref();
17 assert.equal(result, 'data:text/csv;charset=utf-8,');
18 });
19
20 it('starts with data:', () => {
21 const result = constructHref('');
22 assert.isTrue(result.startsWith('data:'));
23 });
24
25 it('uses charset=utf-8', () => {
26 const result = constructHref('');
27 assert.isTrue(result.search('charset=utf-8') > -1);
28 });
29
30 it('encodes URI component', () => {
31 const encodeFuncStub = sinon.stub(window, 'encodeURIComponent');
32 constructHref('');
33 sinon.assert.calledOnce(encodeFuncStub);
34
35 window.encodeURIComponent.restore();
36 });
37
38 it('encodes URI component', () => {
39 const input = 'foo, bar fizz=buzz';
40 const expected = 'foo%2C%20bar%20fizz%3Dbuzz';
41 const output = constructHref(input);
42
43 assert.equal(expected, output.split(',')[1]);
44 });
45});
46
47describe('convertListContentToCsv', () => {
48 it('joins rows with carriage return and line feed, CRLF', () => {
49 const input = [['foobar'], ['fizzbuzz']];
50 const expected = '"foobar"\r\n"fizzbuzz"';
51 assert.equal(expected, convertListContentToCsv(input));
52 });
53
54 it('joins columns with commas', () => {
55 const input = [['foo', 'bar', 'fizz', 'buzz']];
56 const expected = '"foo","bar","fizz","buzz"';
57 assert.equal(expected, convertListContentToCsv(input));
58 });
59
60 it('starts with non-empty row', () => {
61 const input = [['foobar']];
62 const expected = '"foobar"';
63 const result = convertListContentToCsv(input);
64 assert.equal(expected, result);
65 assert.isFalse(result.startsWith('\r\n'));
66 });
67});
68
69describe('prepareDataForDownload', () => {
70 it('prepends header row', () => {
71 const headers = ['column1', 'column2'];
72 const result = prepareDataForDownload([['a', 'b']], headers);
73
74 const expected = `"column1","column2"`;
75 assert.equal(expected, result.split('\r\n')[0]);
76 assert.isTrue(result.startsWith(expected));
77 });
78});
79
80describe('preventCSVInjectionAndStringify', () => {
81 it('prepends all double quotes with another double quote', () => {
82 let input = '"hello world"';
83 let expect = '""hello world""';
84 assert.equal(expect, preventCSVInjectionAndStringify(input).slice(1, -1));
85
86 input = 'Just a double quote: " ';
87 expect = 'Just a double quote: "" ';
88 assert.equal(expect, preventCSVInjectionAndStringify(input).slice(1, -1));
89
90 input = 'Multiple"double"quotes"""';
91 expect = 'Multiple""double""quotes""""""';
92 assert.equal(expect, preventCSVInjectionAndStringify(input).slice(1, -1));
93 });
94
95 it('wraps string with double quotes', () => {
96 let input = '"hello world"';
97 let expected = preventCSVInjectionAndStringify(input);
98 assert.equal('"', expected[0]);
99 assert.equal('"', expected[expected.length-1]);
100
101 input = 'For unevent quotes too: " ';
102 expected = '"For unevent quotes too: "" "';
103 assert.equal(expected, preventCSVInjectionAndStringify(input));
104
105 input = 'And for ending quotes"""';
106 expected = '"And for ending quotes"""""""';
107 assert.equal(expected, preventCSVInjectionAndStringify(input));
108 });
109
110 it('wraps strings containing commas with double quotes', () => {
111 const input = 'Let\'s, add, a bunch, of, commas,';
112 const expected = '"Let\'s, add, a bunch, of, commas,"';
113 assert.equal(expected, preventCSVInjectionAndStringify(input));
114 });
115
116 it('can handle strings containing commas and new line chars', () => {
117 const input = `""new"",\r\nline "" "",\r\nand 'end', and end`;
118 const expected = `"""""new"""",\r\nline """" """",\r\nand 'end', and end"`;
119 assert.equal(expected, preventCSVInjectionAndStringify(input));
120 });
121
122 it('preserves single quotes', () => {
123 let input = `all the 'single' quotes`;
124 let expected = `"all the 'single' quotes"`;
125 assert.equal(expected, preventCSVInjectionAndStringify(input));
126
127 input = `''''' fives single quotes before and after '''''`;
128 expected = `"''''' fives single quotes before and after '''''"`;
129 assert.equal(expected, preventCSVInjectionAndStringify(input));
130 });
131
132 it('prevents csv injection', () => {
133 let input = `@@Should prepend with single quote`;
134 let expected = `"'@@Should prepend with single quote"`;
135 assert.equal(expected, preventCSVInjectionAndStringify(input));
136
137 input = `at symbol @ later on, do not expect ' at start`;
138 expected = `"at symbol @ later on, do not expect ' at start"`;
139 assert.equal(expected, preventCSVInjectionAndStringify(input));
140
141 input = `==@+=--@Should prepend with single quote`;
142 expected = `"'==@+=--@Should prepend with single quote"`;
143 assert.equal(expected, preventCSVInjectionAndStringify(input));
144 });
145});