model.spec.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import expect = require('expect.js');
  4. import { DSVModel } from '@jupyterlab/csvviewer';
  5. /* tslint:disable:no-var-requires */
  6. const CSV_TEST_FILES = [
  7. [
  8. 'comma_in_quotes',
  9. require('csv-spectrum/csvs/comma_in_quotes.csv'),
  10. require('csv-spectrum/json/comma_in_quotes.json')
  11. ],
  12. [
  13. 'empty',
  14. require('csv-spectrum/csvs/empty.csv'),
  15. require('csv-spectrum/json/empty.json')
  16. ],
  17. [
  18. 'empty_crlf',
  19. require('csv-spectrum/csvs/empty_crlf.csv'),
  20. require('csv-spectrum/json/empty_crlf.json')
  21. ],
  22. [
  23. 'escaped_quotes',
  24. require('csv-spectrum/csvs/escaped_quotes.csv'),
  25. require('csv-spectrum/json/escaped_quotes.json')
  26. ],
  27. [
  28. 'json',
  29. require('csv-spectrum/csvs/json.csv'),
  30. require('csv-spectrum/json/json.json')
  31. ],
  32. [
  33. 'newlines',
  34. require('csv-spectrum/csvs/newlines.csv'),
  35. require('csv-spectrum/json/newlines.json')
  36. ],
  37. [
  38. 'newlines_crlf',
  39. require('csv-spectrum/csvs/newlines_crlf.csv'),
  40. require('csv-spectrum/json/newlines_crlf.json')
  41. ],
  42. [
  43. 'quotes_and_newlines',
  44. require('csv-spectrum/csvs/quotes_and_newlines.csv'),
  45. require('csv-spectrum/json/quotes_and_newlines.json')
  46. ],
  47. [
  48. 'simple',
  49. require('csv-spectrum/csvs/simple.csv'),
  50. require('csv-spectrum/json/simple.json')
  51. ],
  52. [
  53. 'simple_crlf',
  54. require('csv-spectrum/csvs/simple_crlf.csv'),
  55. require('csv-spectrum/json/simple_crlf.json')
  56. ],
  57. [
  58. 'utf8',
  59. require('csv-spectrum/csvs/utf8.csv'),
  60. require('csv-spectrum/json/utf8.json')
  61. ]
  62. ];
  63. /* tslint:enable:no-var-requires */
  64. describe('csvviewer/model', () => {
  65. describe('DSVModel', () => {
  66. describe('#constructor()', () => {
  67. it('should instantiate a `DSVModel`', () => {
  68. let d = new DSVModel({ data: 'a,b,c\nd,e,f\n', delimiter: ',' });
  69. expect(d.rowCount('column-header')).to.be(1);
  70. expect(d.rowCount('body')).to.be(1);
  71. expect(d.columnCount('row-header')).to.be(1);
  72. expect(d.columnCount('body')).to.be(3);
  73. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  74. 'a',
  75. 'b',
  76. 'c'
  77. ]);
  78. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql([
  79. 'd',
  80. 'e',
  81. 'f'
  82. ]);
  83. });
  84. });
  85. it('parses a number of test files correctly', () => {
  86. for (let [, csv, answer] of CSV_TEST_FILES) {
  87. let d = new DSVModel({ data: csv, delimiter: ',' });
  88. let labels = [];
  89. for (let i = 0; i < d.columnCount('body'); i++) {
  90. labels.push(d.data('column-header', 0, i));
  91. }
  92. let values = [];
  93. for (let r = 0; r < d.rowCount('body'); r++) {
  94. let row: { [key: string]: string } = {};
  95. for (let c = 0; c < d.columnCount('body'); c++) {
  96. row[labels[c]] = d.data('body', r, c);
  97. }
  98. values.push(row);
  99. }
  100. expect(values).to.eql(answer);
  101. }
  102. });
  103. it('handles tab-separated data', () => {
  104. let d = new DSVModel({ data: 'a\tb\tc\nd\te\tf\n', delimiter: '\t' });
  105. expect(d.rowCount('column-header')).to.be(1);
  106. expect(d.rowCount('body')).to.be(1);
  107. expect(d.columnCount('row-header')).to.be(1);
  108. expect(d.columnCount('body')).to.be(3);
  109. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  110. 'a',
  111. 'b',
  112. 'c'
  113. ]);
  114. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql(['d', 'e', 'f']);
  115. });
  116. it('handles not having a header', () => {
  117. let d = new DSVModel({
  118. data: 'a,b,c\nd,e,f\n',
  119. delimiter: ',',
  120. header: false
  121. });
  122. expect(d.rowCount('column-header')).to.be(1);
  123. expect(d.rowCount('body')).to.be(2);
  124. expect(d.columnCount('row-header')).to.be(1);
  125. expect(d.columnCount('body')).to.be(3);
  126. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  127. '1',
  128. '2',
  129. '3'
  130. ]);
  131. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql(['a', 'b', 'c']);
  132. expect([0, 1, 2].map(i => d.data('body', 1, i))).to.eql(['d', 'e', 'f']);
  133. });
  134. it('handles having only a header', () => {
  135. let d = new DSVModel({ data: 'a,b,c\n', delimiter: ',', header: true });
  136. expect(d.rowCount('column-header')).to.be(1);
  137. expect(d.rowCount('body')).to.be(0);
  138. expect(d.columnCount('row-header')).to.be(1);
  139. expect(d.columnCount('body')).to.be(3);
  140. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  141. 'a',
  142. 'b',
  143. 'c'
  144. ]);
  145. });
  146. it('handles single non-header line', () => {
  147. let d = new DSVModel({ data: 'a,b,c\n', delimiter: ',', header: false });
  148. expect(d.rowCount('column-header')).to.be(1);
  149. expect(d.rowCount('body')).to.be(1);
  150. expect(d.columnCount('row-header')).to.be(1);
  151. expect(d.columnCount('body')).to.be(3);
  152. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  153. '1',
  154. '2',
  155. '3'
  156. ]);
  157. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql(['a', 'b', 'c']);
  158. });
  159. it('handles CRLF row delimiter', () => {
  160. let d = new DSVModel({
  161. data: 'a,b,c\r\nd,e,f\r\n',
  162. delimiter: ',',
  163. rowDelimiter: '\r\n'
  164. });
  165. expect(d.rowCount('column-header')).to.be(1);
  166. expect(d.rowCount('body')).to.be(1);
  167. expect(d.columnCount('row-header')).to.be(1);
  168. expect(d.columnCount('body')).to.be(3);
  169. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  170. 'a',
  171. 'b',
  172. 'c'
  173. ]);
  174. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql(['d', 'e', 'f']);
  175. });
  176. it('handles CR row delimiter', () => {
  177. let d = new DSVModel({
  178. data: 'a,b,c\rd,e,f\r',
  179. delimiter: ',',
  180. rowDelimiter: '\r'
  181. });
  182. expect(d.rowCount('column-header')).to.be(1);
  183. expect(d.rowCount('body')).to.be(1);
  184. expect(d.columnCount('row-header')).to.be(1);
  185. expect(d.columnCount('body')).to.be(3);
  186. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  187. 'a',
  188. 'b',
  189. 'c'
  190. ]);
  191. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql(['d', 'e', 'f']);
  192. });
  193. it('can guess the row delimiter', () => {
  194. let d = new DSVModel({ data: 'a,b,c\rd,e,f\r', delimiter: ',' });
  195. expect(d.rowCount('column-header')).to.be(1);
  196. expect(d.rowCount('body')).to.be(1);
  197. expect(d.columnCount('row-header')).to.be(1);
  198. expect(d.columnCount('body')).to.be(3);
  199. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  200. 'a',
  201. 'b',
  202. 'c'
  203. ]);
  204. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql(['d', 'e', 'f']);
  205. });
  206. it('handles a given quote character', () => {
  207. let d = new DSVModel({
  208. data: `a,'b','c'\r'd',e,'f'\r`,
  209. delimiter: ',',
  210. quote: `'`
  211. });
  212. expect(d.rowCount('column-header')).to.be(1);
  213. expect(d.rowCount('body')).to.be(1);
  214. expect(d.columnCount('row-header')).to.be(1);
  215. expect(d.columnCount('body')).to.be(3);
  216. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  217. 'a',
  218. 'b',
  219. 'c'
  220. ]);
  221. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql(['d', 'e', 'f']);
  222. });
  223. it('handles delimiters and quotes inside quotes', () => {
  224. let d = new DSVModel({
  225. data: `'a\rx',b,'c''x'\r'd,x',e,'f'\r`,
  226. delimiter: ',',
  227. quote: `'`,
  228. rowDelimiter: '\r'
  229. });
  230. expect(d.rowCount('column-header')).to.be(1);
  231. expect(d.rowCount('body')).to.be(1);
  232. expect(d.columnCount('row-header')).to.be(1);
  233. expect(d.columnCount('body')).to.be(3);
  234. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  235. 'a\rx',
  236. 'b',
  237. `c'x`
  238. ]);
  239. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql([
  240. 'd,x',
  241. 'e',
  242. 'f'
  243. ]);
  244. });
  245. it('handles rows that are too short or too long', () => {
  246. let d = new DSVModel({ data: `a,b,c\n,c,d,e,f\ng,h`, delimiter: ',' });
  247. expect(d.rowCount('column-header')).to.be(1);
  248. expect(d.rowCount('body')).to.be(2);
  249. expect(d.columnCount('row-header')).to.be(1);
  250. expect(d.columnCount('body')).to.be(3);
  251. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  252. 'a',
  253. 'b',
  254. 'c'
  255. ]);
  256. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql([
  257. '',
  258. 'c',
  259. 'd,e,f'
  260. ]);
  261. expect([0, 1, 2].map(i => d.data('body', 1, i))).to.eql(['g', 'h', '']);
  262. });
  263. it('handles delayed parsing of rows past the initial rows', () => {
  264. let d = new DSVModel({
  265. data: `a,b,c\nc,d,e\nf,g,h\ni,j,k`,
  266. delimiter: ',',
  267. initialRows: 2
  268. });
  269. expect(d.rowCount('column-header')).to.be(1);
  270. expect(d.rowCount('body')).to.be(1);
  271. expect(d.columnCount('row-header')).to.be(1);
  272. expect(d.columnCount('body')).to.be(3);
  273. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  274. 'a',
  275. 'b',
  276. 'c'
  277. ]);
  278. // Expected behavior is that all unparsed data is lumped into the final field.
  279. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql([
  280. 'c',
  281. 'd',
  282. 'e\nf,g,h\ni,j,k'
  283. ]);
  284. // Check everything is in order after all the data has been parsed asynchronously.
  285. return d.ready.then(() => {
  286. expect(d.rowCount('column-header')).to.be(1);
  287. expect(d.rowCount('body')).to.be(3);
  288. expect(d.columnCount('row-header')).to.be(1);
  289. expect(d.columnCount('body')).to.be(3);
  290. expect([0, 1, 2].map(i => d.data('column-header', 0, i))).to.eql([
  291. 'a',
  292. 'b',
  293. 'c'
  294. ]);
  295. expect([0, 1, 2].map(i => d.data('body', 0, i))).to.eql([
  296. 'c',
  297. 'd',
  298. 'e'
  299. ]);
  300. expect([0, 1, 2].map(i => d.data('body', 1, i))).to.eql([
  301. 'f',
  302. 'g',
  303. 'h'
  304. ]);
  305. expect([0, 1, 2].map(i => d.data('body', 2, i))).to.eql([
  306. 'i',
  307. 'j',
  308. 'k'
  309. ]);
  310. });
  311. });
  312. });
  313. });