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));
+  });
+});