Project import generated by Copybara.
GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/static_src/elements/framework/mr-issue-list/list-to-csv-helpers.test.js b/static_src/elements/framework/mr-issue-list/list-to-csv-helpers.test.js
new file mode 100644
index 0000000..cd124a5
--- /dev/null
+++ b/static_src/elements/framework/mr-issue-list/list-to-csv-helpers.test.js
@@ -0,0 +1,145 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assert} from 'chai';
+import sinon from 'sinon';
+import {
+ constructHref,
+ convertListContentToCsv,
+ prepareDataForDownload,
+ preventCSVInjectionAndStringify,
+} from './list-to-csv-helpers.js';
+
+describe('constructHref', () => {
+ it('has default of empty string', () => {
+ const result = constructHref();
+ assert.equal(result, 'data:text/csv;charset=utf-8,');
+ });
+
+ it('starts with data:', () => {
+ const result = constructHref('');
+ assert.isTrue(result.startsWith('data:'));
+ });
+
+ it('uses charset=utf-8', () => {
+ const result = constructHref('');
+ assert.isTrue(result.search('charset=utf-8') > -1);
+ });
+
+ it('encodes URI component', () => {
+ const encodeFuncStub = sinon.stub(window, 'encodeURIComponent');
+ constructHref('');
+ sinon.assert.calledOnce(encodeFuncStub);
+
+ window.encodeURIComponent.restore();
+ });
+
+ it('encodes URI component', () => {
+ const input = 'foo, bar fizz=buzz';
+ const expected = 'foo%2C%20bar%20fizz%3Dbuzz';
+ const output = constructHref(input);
+
+ assert.equal(expected, output.split(',')[1]);
+ });
+});
+
+describe('convertListContentToCsv', () => {
+ it('joins rows with carriage return and line feed, CRLF', () => {
+ const input = [['foobar'], ['fizzbuzz']];
+ const expected = '"foobar"\r\n"fizzbuzz"';
+ assert.equal(expected, convertListContentToCsv(input));
+ });
+
+ it('joins columns with commas', () => {
+ const input = [['foo', 'bar', 'fizz', 'buzz']];
+ const expected = '"foo","bar","fizz","buzz"';
+ assert.equal(expected, convertListContentToCsv(input));
+ });
+
+ it('starts with non-empty row', () => {
+ const input = [['foobar']];
+ const expected = '"foobar"';
+ const result = convertListContentToCsv(input);
+ assert.equal(expected, result);
+ assert.isFalse(result.startsWith('\r\n'));
+ });
+});
+
+describe('prepareDataForDownload', () => {
+ it('prepends header row', () => {
+ const headers = ['column1', 'column2'];
+ const result = prepareDataForDownload([['a', 'b']], headers);
+
+ const expected = `"column1","column2"`;
+ assert.equal(expected, result.split('\r\n')[0]);
+ assert.isTrue(result.startsWith(expected));
+ });
+});
+
+describe('preventCSVInjectionAndStringify', () => {
+ it('prepends all double quotes with another double quote', () => {
+ let input = '"hello world"';
+ let expect = '""hello world""';
+ assert.equal(expect, preventCSVInjectionAndStringify(input).slice(1, -1));
+
+ input = 'Just a double quote: " ';
+ expect = 'Just a double quote: "" ';
+ assert.equal(expect, preventCSVInjectionAndStringify(input).slice(1, -1));
+
+ input = 'Multiple"double"quotes"""';
+ expect = 'Multiple""double""quotes""""""';
+ assert.equal(expect, preventCSVInjectionAndStringify(input).slice(1, -1));
+ });
+
+ it('wraps string with double quotes', () => {
+ let input = '"hello world"';
+ let expected = preventCSVInjectionAndStringify(input);
+ assert.equal('"', expected[0]);
+ assert.equal('"', expected[expected.length-1]);
+
+ input = 'For unevent quotes too: " ';
+ expected = '"For unevent quotes too: "" "';
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+
+ input = 'And for ending quotes"""';
+ expected = '"And for ending quotes"""""""';
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+ });
+
+ it('wraps strings containing commas with double quotes', () => {
+ const input = 'Let\'s, add, a bunch, of, commas,';
+ const expected = '"Let\'s, add, a bunch, of, commas,"';
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+ });
+
+ it('can handle strings containing commas and new line chars', () => {
+ const input = `""new"",\r\nline "" "",\r\nand 'end', and end`;
+ const expected = `"""""new"""",\r\nline """" """",\r\nand 'end', and end"`;
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+ });
+
+ it('preserves single quotes', () => {
+ let input = `all the 'single' quotes`;
+ let expected = `"all the 'single' quotes"`;
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+
+ input = `''''' fives single quotes before and after '''''`;
+ expected = `"''''' fives single quotes before and after '''''"`;
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+ });
+
+ it('prevents csv injection', () => {
+ let input = `@@Should prepend with single quote`;
+ let expected = `"'@@Should prepend with single quote"`;
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+
+ input = `at symbol @ later on, do not expect ' at start`;
+ expected = `"at symbol @ later on, do not expect ' at start"`;
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+
+ input = `==@+=--@Should prepend with single quote`;
+ expected = `"'==@+=--@Should prepend with single quote"`;
+ assert.equal(expected, preventCSVInjectionAndStringify(input));
+ });
+});