瀏覽代碼

Clean up tests and add a bunch of quoted field tests.

Jason Grout 7 年之前
父節點
當前提交
061075f7f7
共有 3 個文件被更改,包括 212 次插入129 次删除
  1. 6 0
      packages/csvviewer/src/parse.ts
  2. 55 64
      tests/test-csvviewer/src/parse-noquotes.spec.ts
  3. 151 65
      tests/test-csvviewer/src/parse.spec.ts

+ 6 - 0
packages/csvviewer/src/parse.ts

@@ -10,6 +10,7 @@ Possible options to add to the parser:
 - Skip rows with empty columns
 - Logging an error for too many or too few fields on a line
 - Ignore whitespace around delimiters
+- Add an exported function in this file for getting a field from the returned offsets array (including stripping field or row delimiters and parsing quoted data). Right now this logic is in the DSVModel. Likely we want to keep the logic there for speed, but having it here as well will make the parser more self-contained and usable by others.
 - Sanity check on field size, with an error if the field exceeds the size
 - Tests against https://github.com/maxogden/csv-spectrum
 - Benchmark against https://www.npmjs.com/package/csv-parser and https://www.npmjs.com/package/csv-string and fast-csv.
@@ -64,6 +65,11 @@ namespace IParser {
 
     /**
      * The quote character for quoting fields. Defaults to the double quote (").
+     *
+     * #### Notes
+     * As specified in [RFC 4180](https://tools.ietf.org/html/rfc4180), quotes
+     * are escaped in a quoted field by doubling them (for example, "a""b" is the field
+     * a"b).
      */
     quote?: string;
 

+ 55 - 64
tests/test-csvviewer/src/parse-noquotes.spec.ts

@@ -4,10 +4,9 @@
 import expect = require('expect.js');
 
 import {
-  parseDSVNoQuotes
+  parseDSVNoQuotes as parser
 } from '@jupyterlab/csvviewer';
 
-let parseDSV = parseDSVNoQuotes;
 
 describe('csvviewer/parsenoquotes', () => {
 
@@ -15,20 +14,18 @@ describe('csvviewer/parsenoquotes', () => {
 
     it('does basic parsing of csv files', () => {
       let data = `a,b,c,d\r\n0,1,2,3\r\n4,5,6,7`;
-      let options = {data, columnOffsets: false};
-      let offsets = parseDSV(options);
-      expect(offsets.nrows).to.eql(3);
-      expect(offsets.ncols).to.eql(0);
-      expect(offsets.offsets).to.eql([0, 9, 18]);
-    });
+      let options = {data};
+      let results;
 
-    it('does basic parsing of csv files with column offsets', () => {
-      let data = `a,b,c,d\r\n0,1,2,3\r\n4,5,6,7`;
-      let options = {data, columnOffsets: true};
-      let offsets = parseDSV(options);
-      expect(offsets.nrows).to.eql(3);
-      expect(offsets.ncols).to.eql(4);
-      expect(offsets.offsets).to.eql([0, 2, 4, 6, 9, 11, 13, 15, 18, 20, 22, 24]);
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.ncols).to.eql(0);
+      expect(results.offsets).to.eql([0, 9, 18]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(3);
+      expect(results.ncols).to.eql(4);
+      expect(results.offsets).to.eql([0, 2, 4, 6, 9, 11, 13, 15, 18, 20, 22, 24]);
     });
 
     // For simplicity, we'll use \n as a row delimiter below.
@@ -38,11 +35,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(3);
       expect(results.offsets).to.eql([0, 8, 16]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]);
@@ -53,11 +50,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, delimiter: '\t', rowDelimiter: '\n'};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(3);
       expect(results.offsets).to.eql([0, 8, 16]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]);
@@ -68,11 +65,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n', startIndex: 8};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(2);
       expect(results.offsets).to.eql([8, 16]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(2);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([8, 10, 12, 14, 16, 18, 20, 22]);
@@ -83,11 +80,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n', maxRows: 2};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(2);
       expect(results.offsets).to.eql([0, 8]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(2);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 12, 14]);
@@ -98,11 +95,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n', startIndex: 8, maxRows: 1};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(1);
       expect(results.offsets).to.eql([8]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([8, 10, 12, 14]);
@@ -113,12 +110,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 8, 11]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 10, 10, 11, 13, 15, 17]);
@@ -129,12 +125,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\r\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 9, 13]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([ 0, 2, 4, 6, 9, 11, 11, 11, 13, 15, 17, 19 ]);
@@ -145,12 +140,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n', ncols: 5};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 8, 11]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(5);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 8, 10, 10, 10, 10, 11, 13, 15, 17, 19]);
@@ -161,12 +155,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\r\n', ncols: 5};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 9, 13]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(5);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 9, 11, 11, 11, 11, 13, 15, 17, 19, 21]);
@@ -177,12 +170,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n', ncols: 7};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(7);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 7, 7]);
@@ -193,11 +185,11 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n', ncols: 7};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(7);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 7, 7]);
@@ -208,27 +200,26 @@ describe('csvviewer/parsenoquotes', () => {
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(1);
       expect(results.offsets).to.eql([0]);
     });
 
-    it('handles adding or deleting columns as necessary', () => {
+    it('handles adding columns or merging columns as necessary', () => {
       let data = `a,b,c\n,c,d,e,f\ng,h`;
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSVNoQuotes({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 6, 15]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(3);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 9, 15, 17, 18]);

+ 151 - 65
tests/test-csvviewer/src/parse.spec.ts

@@ -4,7 +4,7 @@
 import expect = require('expect.js');
 
 import {
-  parseDSV
+  parseDSV as parser
 } from '@jupyterlab/csvviewer';
 
 describe('csvviewer/parse', () => {
@@ -13,20 +13,18 @@ describe('csvviewer/parse', () => {
 
     it('does basic parsing of csv files', () => {
       let data = `a,b,c,d\r\n0,1,2,3\r\n4,5,6,7`;
-      let options = {data, columnOffsets: false};
-      let offsets = parseDSV(options);
-      expect(offsets.nrows).to.eql(3);
-      expect(offsets.ncols).to.eql(0);
-      expect(offsets.offsets).to.eql([0, 9, 18]);
-    });
+      let options = {data};
+      let results;
 
-    it('does basic parsing of csv files with column offsets', () => {
-      let data = `a,b,c,d\r\n0,1,2,3\r\n4,5,6,7`;
-      let options = {data, columnOffsets: true};
-      let offsets = parseDSV(options);
-      expect(offsets.nrows).to.eql(3);
-      expect(offsets.ncols).to.eql(4);
-      expect(offsets.offsets).to.eql([0, 2, 4, 6, 9, 11, 13, 15, 18, 20, 22, 24]);
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.ncols).to.eql(0);
+      expect(results.offsets).to.eql([0, 9, 18]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(3);
+      expect(results.ncols).to.eql(4);
+      expect(results.offsets).to.eql([0, 2, 4, 6, 9, 11, 13, 15, 18, 20, 22, 24]);
     });
 
     // For simplicity, we'll use \n as a row delimiter below.
@@ -36,11 +34,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(3);
       expect(results.offsets).to.eql([0, 8, 16]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]);
@@ -51,11 +49,11 @@ describe('csvviewer/parse', () => {
       let options = {data, delimiter: '\t', rowDelimiter: '\n'};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(3);
       expect(results.offsets).to.eql([0, 8, 16]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]);
@@ -66,11 +64,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n', startIndex: 8};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(2);
       expect(results.offsets).to.eql([8, 16]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(2);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([8, 10, 12, 14, 16, 18, 20, 22]);
@@ -81,11 +79,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n', maxRows: 2};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(2);
       expect(results.offsets).to.eql([0, 8]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(2);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 12, 14]);
@@ -96,11 +94,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n', startIndex: 8, maxRows: 1};
       let results;
 
-      results = parseDSV({...options, columnOffsets: false});
+      results = parser({...options, columnOffsets: false});
       expect(results.nrows).to.eql(1);
       expect(results.offsets).to.eql([8]);
 
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([8, 10, 12, 14]);
@@ -111,12 +109,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 8, 11]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([0, 2, 4, 6, 8, 10, 10, 10, 11, 13, 15, 17]);
@@ -127,12 +124,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\r\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 9, 13]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(4);
       expect(results.offsets).to.eql([ 0, 2, 4, 6, 9, 11, 11, 11, 13, 15, 17, 19 ]);
@@ -143,12 +139,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n', ncols: 5};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 8, 11]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(5);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 8, 10, 10, 10, 10, 11, 13, 15, 17, 19]);
@@ -159,12 +154,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\r\n', ncols: 5};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 9, 13]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(5);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 9, 11, 11, 11, 11, 13, 15, 17, 19, 21]);
@@ -175,12 +169,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n', ncols: 7};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(7);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 7, 7]);
@@ -191,11 +184,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n', ncols: 7};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(7);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 7, 7]);
@@ -206,12 +199,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(1);
       expect(results.offsets).to.eql([0]);
@@ -222,12 +214,11 @@ describe('csvviewer/parse', () => {
       let options = {data, rowDelimiter: '\n'};
       let results;
 
-      // results = parseDSV({...options, columnOffsets: false});
-      // expect(results.nrows).to.eql(3);
-      // expect(results.offsets).to.eql([0, 8, 12]);
-
-      results = parseDSV({...options, columnOffsets: true});
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(3);
+      expect(results.offsets).to.eql([0, 6, 15]);
 
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(3);
       expect(results.ncols).to.eql(3);
       expect(results.offsets).to.eql([0, 2, 4, 6, 7, 9, 15, 17, 18]);
@@ -236,20 +227,115 @@ describe('csvviewer/parse', () => {
   });
 
   describe('parseDSV quotes', () => {
+
     it('does basic parsing of quoted csv files', () => {
       let data = `first,"last",address,city,zip`;
       let options = {data, rowDelimiter: '\n'};
       let results;
-      results = parseDSV({...options, columnOffsets: true});
 
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
+
+      results = parser({...options, columnOffsets: true});
       expect(results.nrows).to.eql(1);
       expect(results.ncols).to.eql(5);
       expect(results.offsets).to.eql([0, 6, 13, 21, 26]);
     });
 
+    it('handles quotes with field delimiters', () => {
+      let data = `a,"b,c",d\n"e","f"`;
+      let options = {data, rowDelimiter: '\n'};
+      let results;
+
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(2);
+      expect(results.offsets).to.eql([0, 10]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(2);
+      expect(results.ncols).to.eql(3);
+      expect(results.offsets).to.eql([0, 2, 8, 10, 14, 17]);
+    });
+
+    it('handles quotes with row delimiters', () => {
+      let data = `a,"b\nc",d\ne,f`;
+      let options = {data, rowDelimiter: '\n'};
+      let results;
+
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(2);
+      expect(results.offsets).to.eql([0, 10]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(2);
+      expect(results.ncols).to.eql(3);
+      expect(results.offsets).to.eql([0, 2, 8, 10, 12, 13]);
+    });
+
+    it('handles quotes with escaped quotes', () => {
+      let data = `a,"b""c",d\ne,f`;
+      let options = {data, rowDelimiter: '\n'};
+      let results;
+
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(2);
+      expect(results.offsets).to.eql([0, 11]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(2);
+      expect(results.ncols).to.eql(3);
+      expect(results.offsets).to.eql([0, 2, 9, 11, 13, 14]);
+    });
+
+    it('handles setting the quote character', () => {
+      let data = `a,'b'',\nc',d\ne,f`;
+      let options = {data, rowDelimiter: '\n', quote: `'`};
+      let results;
+
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(2);
+      expect(results.offsets).to.eql([0, 13]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(2);
+      expect(results.ncols).to.eql(3);
+      expect(results.offsets).to.eql([0, 2, 11, 13, 15, 16]);
+    });
+
+    it('handles single quoted field', () => {
+      let data = `"a"`;
+      let options = {data, rowDelimiter: '\n'};
+      let results;
+
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(1);
+      expect(results.ncols).to.eql(1);
+      expect(results.offsets).to.eql([0]);
+    });
+
+    it('handles empty quoted field', () => {
+      let data = `a,"",b`;
+      let options = {data, rowDelimiter: '\n'};
+      let results;
+
+      results = parser({...options, columnOffsets: false});
+      expect(results.nrows).to.eql(1);
+      expect(results.offsets).to.eql([0]);
+
+      results = parser({...options, columnOffsets: true});
+      expect(results.nrows).to.eql(1);
+      expect(results.ncols).to.eql(3);
+      expect(results.offsets).to.eql([0, 2, 5]);
+    });
+
   });
 });
 
+// Helpful debugging logging
 // console.log(Array.from(results.offsets));
-// console.log(Array.from(results.offsets).map(i => data[i]));
 // console.log(Array.from(results.offsets).map((i, ind, arr) => data.slice(i, arr[ind + 1])));